feat: support repository and filesystem scan (#503)

* refactor: embed config

* refactor: replace image and layer with artifact and blob

* feat(config): add ArtifactConfig

* fix(scanner): use Artifact

* test(scanner): update mocks

* feat: add repo and fs subcommands

* chore(mod): update

* refactor: fix warn message

* feat(cli): add --no-progress to repo and fs

* mod: Update fanal dependency

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

Co-authored-by: Simarpreet Singh <simar@linux.com>
This commit is contained in:
Teppei Fukuda
2020-05-30 19:46:12 +03:00
committed by GitHub
parent 03ad8a3cd0
commit 2f2d1a908b
47 changed files with 1482 additions and 1025 deletions

2
go.mod
View File

@@ -3,7 +3,7 @@ module github.com/aquasecurity/trivy
go 1.13
require (
github.com/aquasecurity/fanal v0.0.0-20200505074551-9239a362deca
github.com/aquasecurity/fanal v0.0.0-20200528202907-79693bf4a058
github.com/aquasecurity/go-dep-parser v0.0.0-20190819075924-ea223f0ef24b
github.com/aquasecurity/trivy-db v0.0.0-20200514134639-7e57e3e02470
github.com/caarlos0/env/v6 v6.0.0

64
go.sum
View File

@@ -40,10 +40,14 @@ github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdko
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM=
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/aquasecurity/fanal v0.0.0-20200505074551-9239a362deca h1:xNs3bLA5k8hySXtV6S6oOc88zDxpL2gXo4Z2qPXmx4c=
github.com/aquasecurity/fanal v0.0.0-20200505074551-9239a362deca/go.mod h1:3H3F3x2XtcdFH3o1LQJEzfu2sS/rf+XufPIngMZrKO4=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/aquasecurity/fanal v0.0.0-20200528202907-79693bf4a058 h1:vNAuJrimb3eqXSFMhZJNf0PVHfzHFnCRMDuhVi7z2Ok=
github.com/aquasecurity/fanal v0.0.0-20200528202907-79693bf4a058/go.mod h1:omM/xBVqAPNzdV/MegrjayEkKEZzI+eUpyjCXpbTMG0=
github.com/aquasecurity/go-dep-parser v0.0.0-20190819075924-ea223f0ef24b h1:55Ulc/gvfWm4ylhVaR7MxOwujRjA6et7KhmUbSgUFf4=
github.com/aquasecurity/go-dep-parser v0.0.0-20190819075924-ea223f0ef24b/go.mod h1:BpNTD9vHfrejKsED9rx04ldM1WIbeyXGYxUrqTVwxVQ=
github.com/aquasecurity/testdocker v0.0.0-20200426142840-5f05bce6f12a h1:hsw7PpiymXP64evn/K7gsj3hWzMqLrdoeE6JkqDocVg=
@@ -54,6 +58,8 @@ github.com/aquasecurity/vuln-list-update v0.0.0-20191016075347-3d158c2bf9a2 h1:x
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/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
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/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.27.1 h1:MXnqY6SlWySaZAqNnXThOvjRFdiiOuKtC6i7baFdNdU=
github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
@@ -92,6 +98,7 @@ github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwc
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -127,18 +134,32 @@ github.com/elazarl/goproxy/ext v0.0.0-20190421051319-9d40249d3c2f h1:AUj1VoZUfhP
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.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agRrHM=
github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
github.com/go-git/go-git-fixtures/v4 v4.0.1 h1:q+IFMfLx200Q3scvt2hN79JsEzy4AmBTp/pqnefH+Bc=
github.com/go-git/go-git-fixtures/v4 v4.0.1/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw=
github.com/go-git/go-git/v5 v5.0.0 h1:k5RWPm4iJwYtfWoxIJy4wJX9ON7ihPeZZYC1fLYDnpg=
github.com/go-git/go-git/v5 v5.0.0/go.mod h1:oYD8y9kWsGINPFJoLdaScGCN6dlKg23blmClfZwtUVA=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
@@ -230,6 +251,9 @@ github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8=
@@ -242,6 +266,8 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY=
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
@@ -259,12 +285,12 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
@@ -292,6 +318,7 @@ github.com/mattn/go-runewidth v0.0.6 h1:V2iyH+aX9C5fsYCpK60U8BYIvmhqxuOL3JZcqc1N
github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -306,6 +333,8 @@ github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8m
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/olekukonko/tablewriter v0.0.2-0.20190607075207-195002e6e56a h1:0LD5FJGQpEyD78OdhX97W75RjYmMjfLPp1ePrk5URxs=
@@ -355,9 +384,13 @@ github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNue
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
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/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
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=
@@ -371,6 +404,8 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2YqsZKovtsgrwcDH1RZhVbTKCjLp47XpqCDs=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/sosedoff/gitkit v0.2.0 h1:cVre9QZvsDzS/v42PSOsf+GCaecvb/CWGX+diP232F8=
github.com/sosedoff/gitkit v0.2.0/go.mod h1:A+o6ZazfVJwetlcHz3ah6th66XcBdsyzLo+aBt/AsK4=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
@@ -406,6 +441,8 @@ github.com/urfave/cli/v2 v2.2.0 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4=
github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
github.com/vdemeester/k8s-pkg-credentialprovider v1.17.4/go.mod h1:inCTmtUdr5KJbreVojo06krnTgaeAz/Z7lynpPk/Q2c=
github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU=
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
@@ -429,14 +466,16 @@ go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975 h1:/Tl7pH94bvbAAHBdZJT947M/+gp0+CqQXDtMRC0fseo=
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/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-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -469,8 +508,8 @@ golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191108221443-4ba9e2ef068c h1:SRpq/kuj/xNci/RdvEs+RSvpfxqvLAzTKuKGlzoGdZQ=
golang.org/x/net v0.0.0-20191108221443-4ba9e2ef068c/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
@@ -479,8 +518,9 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -490,6 +530,7 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -505,6 +546,7 @@ golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775 h1:TC0v2RSO1u2kn1ZugjrFXkRZAEaqMN/RW+OTZkBzmLE=
golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -537,6 +579,7 @@ golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgw
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191011211836-4c025a95b26e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200210192313-1ace956b0e17 h1:a/Fd23DJvg1CaeDH0dYHahE+hCI0v9rFgxSNIThoUcM=
@@ -573,8 +616,9 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/cheggaaa/pb.v1 v1.0.28 h1:n1tBJnnK2r7g9OW2btFH91V92STTUevLXYFb8gy9EMk=
gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
@@ -592,6 +636,8 @@ gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@@ -12,9 +12,9 @@ import (
"github.com/aquasecurity/trivy-db/pkg/db"
"github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy/internal/artifact"
"github.com/aquasecurity/trivy/internal/client"
"github.com/aquasecurity/trivy/internal/server"
"github.com/aquasecurity/trivy/internal/standalone"
tdb "github.com/aquasecurity/trivy/pkg/db"
"github.com/aquasecurity/trivy/pkg/utils"
"github.com/aquasecurity/trivy/pkg/vulnerability"
@@ -240,10 +240,12 @@ func NewApp(version string) *cli.App {
app.Flags = flags
app.Commands = []*cli.Command{
NewImageCommand(),
NewFilesystemCommand(),
NewRepositoryCommand(),
NewClientCommand(),
NewServerCommand(),
}
app.Action = standalone.Run
app.Action = artifact.ImageRun
return app
}
@@ -320,11 +322,65 @@ func NewImageCommand() *cli.Command {
Name: "image",
Aliases: []string{"i"},
Usage: "scan an image",
Action: standalone.Run,
Action: artifact.ImageRun,
Flags: imageFlags,
}
}
func NewFilesystemCommand() *cli.Command {
return &cli.Command{
Name: "filesystem",
Aliases: []string{"fs"},
Usage: "scan local filesystem",
Action: artifact.FilesystemRun,
Flags: []cli.Flag{
&templateFlag,
&formatFlag,
&inputFlag,
&severityFlag,
&outputFlag,
&exitCodeFlag,
&clearCacheFlag,
&quietFlag,
&ignoreUnfixedFlag,
&debugFlag,
&removedPkgsFlag,
&vulnTypeFlag,
&ignoreFileFlag,
&cacheDirFlag,
&timeoutFlag,
&noProgressFlag,
},
}
}
func NewRepositoryCommand() *cli.Command {
return &cli.Command{
Name: "repository",
Aliases: []string{"repo"},
Usage: "scan remote repository",
Action: artifact.RepositoryRun,
Flags: []cli.Flag{
&templateFlag,
&formatFlag,
&inputFlag,
&severityFlag,
&outputFlag,
&exitCodeFlag,
&clearCacheFlag,
&quietFlag,
&ignoreUnfixedFlag,
&debugFlag,
&removedPkgsFlag,
&vulnTypeFlag,
&ignoreFileFlag,
&cacheDirFlag,
&timeoutFlag,
&noProgressFlag,
},
}
}
func NewClientCommand() *cli.Command {
return &cli.Command{
Name: "client",

View File

@@ -9,12 +9,11 @@ import (
type Config struct {
config.GlobalConfig
config.ArtifactConfig
config.DBConfig
config.ImageConfig
config.ReportConfig
NoProgress bool
// deprecated
onlyUpdate string
// deprecated
@@ -30,12 +29,11 @@ func New(c *cli.Context) (Config, error) {
}
return Config{
GlobalConfig: gc,
DBConfig: config.NewDBConfig(c),
ImageConfig: config.NewImageConfig(c),
ReportConfig: config.NewReportConfig(c),
NoProgress: c.Bool("no-progress"),
GlobalConfig: gc,
ArtifactConfig: config.NewArtifactConfig(c),
DBConfig: config.NewDBConfig(c),
ImageConfig: config.NewImageConfig(c),
ReportConfig: config.NewReportConfig(c),
onlyUpdate: c.String("only-update"),
refresh: c.Bool("refresh"),
@@ -43,7 +41,7 @@ func New(c *cli.Context) (Config, error) {
}, nil
}
func (c *Config) Init() error {
func (c *Config) Init(image bool) error {
if err := c.ReportConfig.Init(c.Logger); err != nil {
return err
}
@@ -59,10 +57,16 @@ func (c *Config) Init() error {
return nil
}
if err := c.ImageConfig.Init(c.Context.Args(), c.Logger); err != nil {
if err := c.ArtifactConfig.Init(c.Context.Args(), c.Logger); err != nil {
cli.ShowAppHelp(c.Context)
return err
}
if image {
if err := c.ImageConfig.Init(c.Context.Args(), c.Logger); err != nil {
return err
}
}
return nil
}

View File

@@ -38,8 +38,8 @@ func TestConfig_Init(t *testing.T) {
GlobalConfig: config.GlobalConfig{
Quiet: true,
},
ImageConfig: config.ImageConfig{
ImageName: "alpine:3.10",
ArtifactConfig: config.ArtifactConfig{
Target: "alpine:3.10",
},
ReportConfig: config.ReportConfig{
Severities: []dbTypes.Severity{dbTypes.SeverityCritical},
@@ -74,8 +74,8 @@ func TestConfig_Init(t *testing.T) {
Output: os.Stdout,
VulnType: []string{"os", "library"},
},
ImageConfig: config.ImageConfig{
ImageName: "centos:7",
ArtifactConfig: config.ArtifactConfig{
Target: "centos:7",
},
},
},
@@ -91,8 +91,8 @@ func TestConfig_Init(t *testing.T) {
Output: os.Stdout,
VulnType: []string{"os", "library"},
},
ImageConfig: config.ImageConfig{
ImageName: "debian:buster",
ArtifactConfig: config.ArtifactConfig{
Target: "debian:buster",
},
onlyUpdate: "alpine",
},
@@ -110,8 +110,8 @@ func TestConfig_Init(t *testing.T) {
VulnType: []string{"os", "library"},
Template: "@contrib/gitlab.tpl",
},
ImageConfig: config.ImageConfig{
ImageName: "gitlab/gitlab-ce:12.7.2-ce.0",
ArtifactConfig: config.ArtifactConfig{
Target: "gitlab/gitlab-ce:12.7.2-ce.0",
},
},
},
@@ -129,8 +129,8 @@ func TestConfig_Init(t *testing.T) {
Template: "@contrib/gitlab.tpl",
Format: "json",
},
ImageConfig: config.ImageConfig{
ImageName: "gitlab/gitlab-ce:12.7.2-ce.0",
ArtifactConfig: config.ArtifactConfig{
Target: "gitlab/gitlab-ce:12.7.2-ce.0",
},
},
},
@@ -147,8 +147,8 @@ func TestConfig_Init(t *testing.T) {
VulnType: []string{"os", "library"},
Format: "template",
},
ImageConfig: config.ImageConfig{
ImageName: "gitlab/gitlab-ce:12.7.2-ce.0",
ArtifactConfig: config.ArtifactConfig{
Target: "gitlab/gitlab-ce:12.7.2-ce.0",
},
},
},
@@ -165,8 +165,8 @@ func TestConfig_Init(t *testing.T) {
Output: os.Stdout,
VulnType: []string{"os", "library"},
},
ImageConfig: config.ImageConfig{
ImageName: "gcr.io/distroless/base",
ArtifactConfig: config.ArtifactConfig{
Target: "gcr.io/distroless/base",
},
autoRefresh: true,
},
@@ -180,7 +180,7 @@ func TestConfig_Init(t *testing.T) {
name: "sad: multiple image names",
args: []string{"centos:7", "alpine:3.10"},
logs: []string{
"multiple images cannot be specified",
"multiple targets cannot be specified",
},
wantErr: "arguments error",
},
@@ -223,7 +223,7 @@ func TestConfig_Init(t *testing.T) {
require.NoError(t, err, err)
c.GlobalConfig.Logger = logger.Sugar()
err = c.Init()
err = c.Init(true)
// tests log messages
var gotMessages []string

36
internal/artifact/fs.go Normal file
View File

@@ -0,0 +1,36 @@
package artifact
import (
"context"
"time"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors"
"github.com/aquasecurity/fanal/cache"
"github.com/aquasecurity/trivy/internal/artifact/config"
"github.com/aquasecurity/trivy/pkg/scanner"
)
func filesystemScanner(ctx context.Context, dir string, ac cache.ArtifactCache, lac cache.LocalArtifactCache, timeout time.Duration) (
scanner.Scanner, func(), error) {
s, cleanup, err := initializeFilesystemScanner(ctx, dir, ac, lac)
if err != nil {
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize a filesystem scanner: %w", err)
}
return s, cleanup, nil
}
func FilesystemRun(cliCtx *cli.Context) error {
c, err := config.New(cliCtx)
if err != nil {
return err
}
// initialize config
if err = c.Init(false); err != nil {
return xerrors.Errorf("failed to initialize options: %w", err)
}
return run(c, filesystemScanner)
}

View File

@@ -0,0 +1,50 @@
package artifact
import (
"context"
"time"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors"
"github.com/aquasecurity/fanal/cache"
"github.com/aquasecurity/trivy/internal/artifact/config"
"github.com/aquasecurity/trivy/pkg/scanner"
)
func archiveScanner(ctx context.Context, input string, ac cache.ArtifactCache, lac cache.LocalArtifactCache, timeout time.Duration) (
scanner.Scanner, func(), error) {
s, err := initializeArchiveScanner(ctx, input, ac, lac, timeout)
if err != nil {
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize the archive scanner: %w", err)
}
return s, func() {}, nil
}
func dockerScanner(ctx context.Context, imageName string, ac cache.ArtifactCache, lac cache.LocalArtifactCache, timeout time.Duration) (
scanner.Scanner, func(), error) {
s, cleanup, err := initializeDockerScanner(ctx, imageName, ac, lac, timeout)
if err != nil {
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize a docker scanner: %w", err)
}
return s, cleanup, nil
}
func ImageRun(cliCtx *cli.Context) error {
c, err := config.New(cliCtx)
if err != nil {
return err
}
// initialize config
if err = c.Init(true); err != nil {
return xerrors.Errorf("failed to initialize options: %w", err)
}
if c.Input != "" {
// scan tar file
return run(c, archiveScanner)
}
return run(c, dockerScanner)
}

View File

@@ -1,6 +1,6 @@
// +build wireinject
package standalone
package artifact
import (
"context"
@@ -12,18 +12,28 @@ import (
"github.com/google/wire"
)
func initializeDockerScanner(ctx context.Context, imageName string, layerCache cache.ImageCache, localImageCache cache.LocalImageCache,
func initializeDockerScanner(ctx context.Context, imageName string, artifactCache cache.ArtifactCache, localArtifactCache cache.LocalArtifactCache,
timeout time.Duration) (scanner.Scanner, func(), error) {
wire.Build(scanner.StandaloneDockerSet)
return scanner.Scanner{}, nil, nil
}
func initializeArchiveScanner(ctx context.Context, filePath string, layerCache cache.ImageCache, localImageCache cache.LocalImageCache,
func initializeArchiveScanner(ctx context.Context, filePath string, artifactCache cache.ArtifactCache, localArtifactCache cache.LocalArtifactCache,
timeout time.Duration) (scanner.Scanner, error) {
wire.Build(scanner.StandaloneArchiveSet)
return scanner.Scanner{}, nil
}
func initializeFilesystemScanner(ctx context.Context, dir string, artifactCache cache.ArtifactCache, localArtifactCache cache.LocalArtifactCache) (scanner.Scanner, func(), error) {
wire.Build(scanner.StandaloneFilesystemSet)
return scanner.Scanner{}, nil, nil
}
func initializeRepositoryScanner(ctx context.Context, url string, artifactCache cache.ArtifactCache, localArtifactCache cache.LocalArtifactCache) (scanner.Scanner, func(), error) {
wire.Build(scanner.StandaloneRepositorySet)
return scanner.Scanner{}, nil, nil
}
func initializeVulnerabilityClient() vulnerability.Client {
wire.Build(vulnerability.SuperSet)
return vulnerability.Client{}

View File

@@ -0,0 +1,36 @@
package artifact
import (
"context"
"time"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors"
"github.com/aquasecurity/fanal/cache"
"github.com/aquasecurity/trivy/internal/artifact/config"
"github.com/aquasecurity/trivy/pkg/scanner"
)
func repositoryScanner(ctx context.Context, dir string, ac cache.ArtifactCache, lac cache.LocalArtifactCache, timeout time.Duration) (
scanner.Scanner, func(), error) {
s, cleanup, err := initializeRepositoryScanner(ctx, dir, ac, lac)
if err != nil {
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize a filesystem scanner: %w", err)
}
return s, cleanup, nil
}
func RepositoryRun(cliCtx *cli.Context) error {
c, err := config.New(cliCtx)
if err != nil {
return err
}
// initialize config
if err = c.Init(false); err != nil {
return xerrors.Errorf("failed to initialize options: %w", err)
}
return run(c, repositoryScanner)
}

View File

@@ -1,17 +1,17 @@
package standalone
package artifact
import (
"context"
l "log"
"os"
"time"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors"
"github.com/aquasecurity/fanal/cache"
"github.com/aquasecurity/trivy-db/pkg/db"
"github.com/aquasecurity/trivy/internal/artifact/config"
"github.com/aquasecurity/trivy/internal/operation"
"github.com/aquasecurity/trivy/internal/standalone/config"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/report"
"github.com/aquasecurity/trivy/pkg/scanner"
@@ -19,24 +19,14 @@ import (
"github.com/aquasecurity/trivy/pkg/utils"
)
func Run(cliCtx *cli.Context) error {
c, err := config.New(cliCtx)
if err != nil {
return err
}
return run(c)
}
type InitializeScanner func(context.Context, string, cache.ArtifactCache, cache.LocalArtifactCache, time.Duration) (
scanner.Scanner, func(), error)
func run(c config.Config) (err error) {
if err = log.InitLogger(c.Debug, c.Quiet); err != nil {
func run(c config.Config, initializeScanner InitializeScanner) error {
if err := log.InitLogger(c.Debug, c.Quiet); err != nil {
l.Fatal(err)
}
// initialize config
if err = c.Init(); err != nil {
return xerrors.Errorf("failed to initialize options: %w", err)
}
// configure cache dir
utils.SetCacheDir(c.CacheDir)
cacheClient, err := cache.NewFSCache(c.CacheDir)
@@ -70,32 +60,25 @@ func run(c config.Config) (err error) {
}
defer db.Close()
var scanner scanner.Scanner
ctx := context.Background()
cleanup := func() {}
target := c.Target
if c.Input != "" {
// scan tar file
scanner, err = initializeArchiveScanner(ctx, c.Input, cacheClient, cacheClient, c.Timeout)
if err != nil {
return xerrors.Errorf("unable to initialize the archive scanner: %w", err)
}
} else {
// scan an image in Docker Engine or Docker Registry
scanner, cleanup, err = initializeDockerScanner(ctx, c.ImageName, cacheClient, cacheClient, c.Timeout)
if err != nil {
return xerrors.Errorf("unable to initialize the docker scanner: %w", err)
}
target = c.Input
}
ctx := context.Background()
scanner, cleanup, err := initializeScanner(ctx, target, cacheClient, cacheClient, c.Timeout)
if err != nil {
return xerrors.Errorf("unable to initialize a scanner: %w", err)
}
defer cleanup()
scanOptions := types.ScanOptions{
VulnType: c.VulnType,
ScanRemovedPackages: c.ScanRemovedPkgs,
ScanRemovedPackages: c.ScanRemovedPkgs, // this is valid only for image subcommand
}
log.Logger.Debugf("Vulnerability type: %s", scanOptions.VulnType)
results, err := scanner.ScanImage(scanOptions)
results, err := scanner.ScanArtifact(ctx, scanOptions)
if err != nil {
return xerrors.Errorf("error in image scan: %w", err)
}

View File

@@ -0,0 +1,96 @@
// Code generated by Wire. DO NOT EDIT.
//go:generate wire
//+build !wireinject
package artifact
import (
"context"
"github.com/aquasecurity/fanal/applier"
image2 "github.com/aquasecurity/fanal/artifact/image"
local2 "github.com/aquasecurity/fanal/artifact/local"
"github.com/aquasecurity/fanal/artifact/remote"
"github.com/aquasecurity/fanal/cache"
"github.com/aquasecurity/fanal/image"
"github.com/aquasecurity/trivy-db/pkg/db"
"github.com/aquasecurity/trivy/pkg/detector/library"
"github.com/aquasecurity/trivy/pkg/detector/ospkg"
"github.com/aquasecurity/trivy/pkg/scanner"
"github.com/aquasecurity/trivy/pkg/scanner/local"
"github.com/aquasecurity/trivy/pkg/types"
"github.com/aquasecurity/trivy/pkg/vulnerability"
"time"
)
// Injectors from inject.go:
func initializeDockerScanner(ctx context.Context, imageName string, artifactCache cache.ArtifactCache, localArtifactCache cache.LocalArtifactCache, timeout time.Duration) (scanner.Scanner, func(), error) {
applierApplier := applier.NewApplier(localArtifactCache)
detector := ospkg.Detector{}
driverFactory := library.DriverFactory{}
libraryDetector := library.NewDetector(driverFactory)
localScanner := local.NewScanner(applierApplier, detector, libraryDetector)
dockerOption, err := types.GetDockerOption(timeout)
if err != nil {
return scanner.Scanner{}, nil, err
}
imageImage, cleanup, err := image.NewDockerImage(ctx, imageName, dockerOption)
if err != nil {
return scanner.Scanner{}, nil, err
}
artifact := image2.NewArtifact(imageImage, artifactCache)
scannerScanner := scanner.NewScanner(localScanner, artifact)
return scannerScanner, func() {
cleanup()
}, nil
}
func initializeArchiveScanner(ctx context.Context, filePath string, artifactCache cache.ArtifactCache, localArtifactCache cache.LocalArtifactCache, timeout time.Duration) (scanner.Scanner, error) {
applierApplier := applier.NewApplier(localArtifactCache)
detector := ospkg.Detector{}
driverFactory := library.DriverFactory{}
libraryDetector := library.NewDetector(driverFactory)
localScanner := local.NewScanner(applierApplier, detector, libraryDetector)
imageImage, err := image.NewArchiveImage(filePath)
if err != nil {
return scanner.Scanner{}, err
}
artifact := image2.NewArtifact(imageImage, artifactCache)
scannerScanner := scanner.NewScanner(localScanner, artifact)
return scannerScanner, nil
}
func initializeFilesystemScanner(ctx context.Context, dir string, artifactCache cache.ArtifactCache, localArtifactCache cache.LocalArtifactCache) (scanner.Scanner, func(), error) {
applierApplier := applier.NewApplier(localArtifactCache)
detector := ospkg.Detector{}
driverFactory := library.DriverFactory{}
libraryDetector := library.NewDetector(driverFactory)
localScanner := local.NewScanner(applierApplier, detector, libraryDetector)
artifact := local2.NewArtifact(dir, artifactCache)
scannerScanner := scanner.NewScanner(localScanner, artifact)
return scannerScanner, func() {
}, nil
}
func initializeRepositoryScanner(ctx context.Context, url string, artifactCache cache.ArtifactCache, localArtifactCache cache.LocalArtifactCache) (scanner.Scanner, func(), error) {
applierApplier := applier.NewApplier(localArtifactCache)
detector := ospkg.Detector{}
driverFactory := library.DriverFactory{}
libraryDetector := library.NewDetector(driverFactory)
localScanner := local.NewScanner(applierApplier, detector, libraryDetector)
artifact, cleanup, err := remote.NewArtifact(url, artifactCache)
if err != nil {
return scanner.Scanner{}, nil, err
}
scannerScanner := scanner.NewScanner(localScanner, artifact)
return scannerScanner, func() {
cleanup()
}, nil
}
func initializeVulnerabilityClient() vulnerability.Client {
config := db.Config{}
client := vulnerability.NewClient(config)
return client
}

View File

@@ -12,6 +12,7 @@ import (
type Config struct {
config.GlobalConfig
config.ArtifactConfig
config.ImageConfig
config.ReportConfig
@@ -31,14 +32,14 @@ func New(c *cli.Context) (Config, error) {
}
return Config{
GlobalConfig: gc,
ImageConfig: config.NewImageConfig(c),
ReportConfig: config.NewReportConfig(c),
RemoteAddr: c.String("remote"),
token: c.String("token"),
tokenHeader: c.String("token-header"),
customHeaders: c.StringSlice("custom-headers"),
GlobalConfig: gc,
ArtifactConfig: config.NewArtifactConfig(c),
ImageConfig: config.NewImageConfig(c),
ReportConfig: config.NewReportConfig(c),
RemoteAddr: c.String("remote"),
token: c.String("token"),
tokenHeader: c.String("token-header"),
customHeaders: c.StringSlice("custom-headers"),
}, nil
}
@@ -59,6 +60,10 @@ func (c *Config) Init() (err error) {
return err
}
if err := c.ArtifactConfig.Init(c.Context.Args(), c.Logger); err != nil {
return err
}
if err := c.ImageConfig.Init(c.Context.Args(), c.Logger); err != nil {
cli.ShowAppHelp(c.Context)
return err

View File

@@ -39,8 +39,8 @@ func TestConfig_Init(t *testing.T) {
GlobalConfig: config.GlobalConfig{
Quiet: true,
},
ImageConfig: config.ImageConfig{
ImageName: "alpine:3.10",
ArtifactConfig: config.ArtifactConfig{
Target: "alpine:3.10",
},
ReportConfig: config.ReportConfig{
Severities: []dbTypes.Severity{dbTypes.SeverityCritical},
@@ -59,8 +59,8 @@ func TestConfig_Init(t *testing.T) {
Output: os.Stdout,
VulnType: []string{"os", "library"},
},
ImageConfig: config.ImageConfig{
ImageName: "alpine:3.11",
ArtifactConfig: config.ArtifactConfig{
Target: "alpine:3.11",
},
token: "secret",
tokenHeader: "X-Trivy-Token",
@@ -78,8 +78,8 @@ func TestConfig_Init(t *testing.T) {
Output: os.Stdout,
VulnType: []string{"os", "library"},
},
ImageConfig: config.ImageConfig{
ImageName: "alpine:3.11",
ArtifactConfig: config.ArtifactConfig{
Target: "alpine:3.11",
},
customHeaders: []string{"foo:bar"},
CustomHeaders: http.Header{
@@ -96,8 +96,8 @@ func TestConfig_Init(t *testing.T) {
Output: os.Stdout,
VulnType: []string{"os", "library"},
},
ImageConfig: config.ImageConfig{
ImageName: "alpine:3.11",
ArtifactConfig: config.ArtifactConfig{
Target: "alpine:3.11",
},
customHeaders: []string{"foobaz"},
CustomHeaders: http.Header{},
@@ -115,8 +115,8 @@ func TestConfig_Init(t *testing.T) {
Output: os.Stdout,
VulnType: []string{"os", "library"},
},
ImageConfig: config.ImageConfig{
ImageName: "centos:7",
ArtifactConfig: config.ArtifactConfig{
Target: "centos:7",
},
CustomHeaders: http.Header{},
},
@@ -134,8 +134,8 @@ func TestConfig_Init(t *testing.T) {
VulnType: []string{"os", "library"},
Template: "@contrib/gitlab.tpl",
},
ImageConfig: config.ImageConfig{
ImageName: "gitlab/gitlab-ce:12.7.2-ce.0",
ArtifactConfig: config.ArtifactConfig{
Target: "gitlab/gitlab-ce:12.7.2-ce.0",
},
CustomHeaders: http.Header{},
},
@@ -154,8 +154,8 @@ func TestConfig_Init(t *testing.T) {
Template: "@contrib/gitlab.tpl",
Format: "json",
},
ImageConfig: config.ImageConfig{
ImageName: "gitlab/gitlab-ce:12.7.2-ce.0",
ArtifactConfig: config.ArtifactConfig{
Target: "gitlab/gitlab-ce:12.7.2-ce.0",
},
CustomHeaders: http.Header{},
},
@@ -173,8 +173,27 @@ func TestConfig_Init(t *testing.T) {
VulnType: []string{"os", "library"},
Format: "template",
},
ImageConfig: config.ImageConfig{
ImageName: "gitlab/gitlab-ce:12.7.2-ce.0",
ArtifactConfig: config.ArtifactConfig{
Target: "gitlab/gitlab-ce:12.7.2-ce.0",
},
CustomHeaders: http.Header{},
},
},
{
name: "invalid option combination: --format template without --template",
args: []string{"--format", "template", "--severity", "MEDIUM", "gitlab/gitlab-ce:12.7.2-ce.0"},
logs: []string{
"--format template is ignored because --template not is specified. Specify --template option when you use --format template.",
},
want: Config{
ReportConfig: config.ReportConfig{
Severities: []dbTypes.Severity{dbTypes.SeverityMedium},
Output: os.Stdout,
VulnType: []string{"os", "library"},
Format: "template",
},
ArtifactConfig: config.ArtifactConfig{
Target: "gitlab/gitlab-ce:12.7.2-ce.0",
},
CustomHeaders: http.Header{},
},
@@ -191,8 +210,8 @@ func TestConfig_Init(t *testing.T) {
Output: os.Stdout,
VulnType: []string{"os", "library"},
},
ImageConfig: config.ImageConfig{
ImageName: "gcr.io/distroless/base",
ArtifactConfig: config.ArtifactConfig{
Target: "gcr.io/distroless/base",
},
CustomHeaders: http.Header{},
},
@@ -201,7 +220,7 @@ func TestConfig_Init(t *testing.T) {
name: "sad: multiple image names",
args: []string{"centos:7", "alpine:3.10"},
logs: []string{
"multiple images cannot be specified",
"multiple targets cannot be specified",
},
wantErr: "arguments error",
},
@@ -234,11 +253,7 @@ func TestConfig_Init(t *testing.T) {
set.String("format", "", "")
set.String("token", "", "")
set.String("token-header", "", "")
//set.String("custom-headers", "", "")
set.Var(&cli.StringSlice{}, "custom-headers", "")
//cli.StringSliceFlag{
// Name: "custom-headers",
//}
ctx := cli.NewContext(app, set, nil)
_ = set.Parse(tt.args)

View File

@@ -13,13 +13,13 @@ import (
"github.com/google/wire"
)
func initializeDockerScanner(ctx context.Context, imageName string, layerCache cache.ImageCache, customHeaders client.CustomHeaders,
func initializeDockerScanner(ctx context.Context, imageName string, artifactCache cache.ArtifactCache, customHeaders client.CustomHeaders,
url client.RemoteURL, timeout time.Duration) (scanner.Scanner, func(), error) {
wire.Build(scanner.RemoteDockerSet)
return scanner.Scanner{}, nil, nil
}
func initializeArchiveScanner(ctx context.Context, filePath string, layerCache cache.ImageCache, customHeaders client.CustomHeaders,
func initializeArchiveScanner(ctx context.Context, filePath string, artifactCache cache.ArtifactCache, customHeaders client.CustomHeaders,
url client.RemoteURL, timeout time.Duration) (scanner.Scanner, error) {
wire.Build(scanner.RemoteArchiveSet)
return scanner.Scanner{}, nil

View File

@@ -58,7 +58,7 @@ func run(c config.Config) (err error) {
}
} else {
// scan an image in Docker Engine or Docker Registry
scanner, cleanup, err = initializeDockerScanner(ctx, c.ImageName, remoteCache,
scanner, cleanup, err = initializeDockerScanner(ctx, c.Target, remoteCache,
client.CustomHeaders(c.CustomHeaders), client.RemoteURL(c.RemoteAddr), c.Timeout)
if err != nil {
return xerrors.Errorf("unable to initialize the docker scanner: %w", err)
@@ -72,7 +72,7 @@ func run(c config.Config) (err error) {
}
log.Logger.Debugf("Vulnerability type: %s", scanOptions.VulnType)
results, err := scanner.ScanImage(scanOptions)
results, err := scanner.ScanArtifact(ctx, scanOptions)
if err != nil {
return xerrors.Errorf("error in image scan: %w", err)
}

View File

@@ -7,9 +7,9 @@ package client
import (
"context"
"github.com/aquasecurity/fanal/analyzer"
image2 "github.com/aquasecurity/fanal/artifact/image"
"github.com/aquasecurity/fanal/cache"
"github.com/aquasecurity/fanal/extractor/docker"
"github.com/aquasecurity/fanal/image"
"github.com/aquasecurity/trivy-db/pkg/db"
"github.com/aquasecurity/trivy/pkg/rpc/client"
"github.com/aquasecurity/trivy/pkg/scanner"
@@ -20,33 +20,33 @@ import (
// Injectors from inject.go:
func initializeDockerScanner(ctx context.Context, imageName string, layerCache cache.ImageCache, customHeaders client.CustomHeaders, url client.RemoteURL, timeout time.Duration) (scanner.Scanner, func(), error) {
func initializeDockerScanner(ctx context.Context, imageName string, artifactCache cache.ArtifactCache, customHeaders client.CustomHeaders, url client.RemoteURL, timeout time.Duration) (scanner.Scanner, func(), error) {
scannerScanner := client.NewProtobufClient(url)
clientScanner := client.NewScanner(customHeaders, scannerScanner)
dockerOption, err := types.GetDockerOption(timeout)
if err != nil {
return scanner.Scanner{}, nil, err
}
extractor, cleanup, err := docker.NewDockerExtractor(ctx, imageName, dockerOption)
imageImage, cleanup, err := image.NewDockerImage(ctx, imageName, dockerOption)
if err != nil {
return scanner.Scanner{}, nil, err
}
config := analyzer.New(extractor, layerCache)
scanner2 := scanner.NewScanner(clientScanner, config)
artifact := image2.NewArtifact(imageImage, artifactCache)
scanner2 := scanner.NewScanner(clientScanner, artifact)
return scanner2, func() {
cleanup()
}, nil
}
func initializeArchiveScanner(ctx context.Context, filePath string, layerCache cache.ImageCache, customHeaders client.CustomHeaders, url client.RemoteURL, timeout time.Duration) (scanner.Scanner, error) {
func initializeArchiveScanner(ctx context.Context, filePath string, artifactCache cache.ArtifactCache, customHeaders client.CustomHeaders, url client.RemoteURL, timeout time.Duration) (scanner.Scanner, error) {
scannerScanner := client.NewProtobufClient(url)
clientScanner := client.NewScanner(customHeaders, scannerScanner)
extractor, err := docker.NewArchiveImageExtractor(filePath)
imageImage, err := image.NewArchiveImage(filePath)
if err != nil {
return scanner.Scanner{}, err
}
config := analyzer.New(extractor, layerCache)
scanner2 := scanner.NewScanner(clientScanner, config)
artifact := image2.NewArtifact(imageImage, artifactCache)
scanner2 := scanner.NewScanner(clientScanner, artifact)
return scanner2, nil
}

View File

@@ -0,0 +1,42 @@
package config
import (
"time"
"github.com/urfave/cli/v2"
"go.uber.org/zap"
"golang.org/x/xerrors"
)
type ArtifactConfig struct {
Input string
Timeout time.Duration
ClearCache bool
// this field is populated in Init()
Target string
}
func NewArtifactConfig(c *cli.Context) ArtifactConfig {
return ArtifactConfig{
Input: c.String("input"),
Timeout: c.Duration("timeout"),
ClearCache: c.Bool("clear-cache"),
}
}
func (c *ArtifactConfig) Init(args cli.Args, logger *zap.SugaredLogger) (err error) {
if c.Input == "" && args.Len() == 0 {
logger.Error(`trivy requires at least 1 argument or --input option`)
return xerrors.New("arguments error")
} else if args.Len() > 1 {
logger.Error(`multiple targets cannot be specified`)
return xerrors.New("arguments error")
}
if c.Input == "" {
c.Target = args.First()
}
return nil
}

View File

@@ -0,0 +1,80 @@
package config_test
import (
"flag"
"testing"
"github.com/aquasecurity/trivy/internal/config"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/urfave/cli/v2"
"go.uber.org/zap"
"go.uber.org/zap/zaptest/observer"
)
func TestArtifactConfig_Init(t *testing.T) {
tests := []struct {
name string
args []string
logs []string
want config.ArtifactConfig
wantErr string
}{
{
name: "happy path",
args: []string{"alpine:3.10"},
want: config.ArtifactConfig{
Target: "alpine:3.10",
},
},
{
name: "sad: multiple image names",
args: []string{"centos:7", "alpine:3.10"},
logs: []string{
"multiple targets cannot be specified",
},
wantErr: "arguments error",
},
{
name: "sad: no image name",
logs: []string{
"trivy requires at least 1 argument or --input option",
},
wantErr: "arguments error",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
core, obs := observer.New(zap.InfoLevel)
logger := zap.New(core)
app := cli.NewApp()
set := flag.NewFlagSet("test", 0)
ctx := cli.NewContext(app, set, nil)
_ = set.Parse(tt.args)
c := config.NewArtifactConfig(ctx)
err := c.Init(ctx.Args(), logger.Sugar())
// tests log messages
var gotMessages []string
for _, entry := range obs.AllUntimed() {
gotMessages = append(gotMessages, entry.Message)
}
assert.Equal(t, tt.logs, gotMessages, tt.name)
// test the error
switch {
case tt.wantErr != "":
require.NotNil(t, err)
assert.Contains(t, err.Error(), tt.wantErr, tt.name)
return
default:
assert.NoError(t, err, tt.name)
}
assert.Equal(t, tt.want, c, tt.name)
})
}
}

View File

@@ -10,6 +10,7 @@ type DBConfig struct {
DownloadDBOnly bool
SkipUpdate bool
Light bool
NoProgress bool
}
func NewDBConfig(c *cli.Context) DBConfig {
@@ -18,6 +19,7 @@ func NewDBConfig(c *cli.Context) DBConfig {
DownloadDBOnly: c.Bool("download-db-only"),
SkipUpdate: c.Bool("skip-update"),
Light: c.Bool("light"),
NoProgress: c.Bool("no-progress"),
}
}

View File

@@ -1,8 +1,6 @@
package config
import (
"time"
"github.com/google/go-containerregistry/pkg/name"
"github.com/urfave/cli/v2"
"go.uber.org/zap"
@@ -10,40 +8,21 @@ import (
)
type ImageConfig struct {
Input string
ScanRemovedPkgs bool
Timeout time.Duration
ClearCache bool
// this field is populated in Init()
ImageName string
}
func NewImageConfig(c *cli.Context) ImageConfig {
return ImageConfig{
Input: c.String("input"),
ScanRemovedPkgs: c.Bool("removed-pkgs"),
Timeout: c.Duration("timeout"),
ClearCache: c.Bool("clear-cache"),
}
}
func (c *ImageConfig) Init(args cli.Args, logger *zap.SugaredLogger) (err error) {
if c.Input == "" && args.Len() == 0 {
logger.Error(`trivy requires at least 1 argument or --input option`)
return xerrors.New("arguments error")
} else if args.Len() > 1 {
logger.Error(`multiple images cannot be specified`)
return xerrors.New("arguments error")
}
if c.Input == "" {
c.ImageName = args.First()
}
imageName := args.First()
// Check whether 'latest' tag is used
if c.ImageName != "" {
ref, err := name.ParseReference(c.ImageName)
if imageName != "" {
ref, err := name.ParseReference(imageName)
if err != nil {
return xerrors.Errorf("invalid image: %w", err)
}

View File

@@ -13,51 +13,16 @@ import (
"github.com/aquasecurity/trivy/internal/config"
)
func TestNewImageConfig(t *testing.T) {
tests := []struct {
name string
args []string
want config.ImageConfig
}{
{
name: "happy path",
args: []string{"--clear-cache", "--input", "/tmp/alpine.tar"},
want: config.ImageConfig{
Input: "/tmp/alpine.tar",
ClearCache: true,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
app := &cli.App{}
set := flag.NewFlagSet("test", 0)
set.Bool("clear-cache", false, "")
set.String("input", "", "")
c := cli.NewContext(app, set, nil)
_ = set.Parse(tt.args)
got := config.NewImageConfig(c)
assert.Equal(t, tt.want, got, tt.name)
})
}
}
func TestImageConfig_Init(t *testing.T) {
tests := []struct {
name string
args []string
logs []string
want config.ImageConfig
wantErr string
}{
{
name: "happy path",
args: []string{"alpine:3.10"},
want: config.ImageConfig{
ImageName: "alpine:3.10",
},
},
{
name: "with latest tag",
@@ -65,24 +30,6 @@ func TestImageConfig_Init(t *testing.T) {
logs: []string{
"You should avoid using the :latest tag as it is cached. You need to specify '--clear-cache' option when :latest image is changed",
},
want: config.ImageConfig{
ImageName: "gcr.io/distroless/base",
},
},
{
name: "sad: multiple image names",
args: []string{"centos:7", "alpine:3.10"},
logs: []string{
"multiple images cannot be specified",
},
wantErr: "arguments error",
},
{
name: "sad: no image name",
logs: []string{
"trivy requires at least 1 argument or --input option",
},
wantErr: "arguments error",
},
{
name: "sad: invalid image name",
@@ -100,7 +47,7 @@ func TestImageConfig_Init(t *testing.T) {
ctx := cli.NewContext(app, set, nil)
_ = set.Parse(tt.args)
c := &config.ImageConfig{}
c := config.NewImageConfig(ctx)
err := c.Init(ctx.Args(), logger.Sugar())
@@ -120,8 +67,6 @@ func TestImageConfig_Init(t *testing.T) {
default:
assert.NoError(t, err, tt.name)
}
assert.Equal(t, &tt.want, c, tt.name)
})
}
}

View File

@@ -17,15 +17,15 @@ import (
var SuperSet = wire.NewSet(
cache.NewFSCache,
wire.Bind(new(cache.LocalImageCache), new(cache.FSCache)),
wire.Bind(new(cache.LocalArtifactCache), new(cache.FSCache)),
NewCache,
)
type Cache struct {
client cache.LocalImageCache
client cache.LocalArtifactCache
}
func NewCache(client cache.LocalImageCache) Cache {
func NewCache(client cache.LocalArtifactCache) Cache {
return Cache{client: client}
}

View File

@@ -28,6 +28,7 @@ func TestNew(t *testing.T) {
DBConfig: config.DBConfig{
Reset: true,
SkipUpdate: true,
NoProgress: true,
},
Listen: "localhost:8080",
},

View File

@@ -1,65 +0,0 @@
// Code generated by Wire. DO NOT EDIT.
//go:generate wire
//+build !wireinject
package standalone
import (
"context"
"github.com/aquasecurity/fanal/analyzer"
"github.com/aquasecurity/fanal/cache"
"github.com/aquasecurity/fanal/extractor/docker"
"github.com/aquasecurity/trivy-db/pkg/db"
"github.com/aquasecurity/trivy/pkg/detector/library"
"github.com/aquasecurity/trivy/pkg/detector/ospkg"
"github.com/aquasecurity/trivy/pkg/scanner"
"github.com/aquasecurity/trivy/pkg/scanner/local"
"github.com/aquasecurity/trivy/pkg/types"
"github.com/aquasecurity/trivy/pkg/vulnerability"
"time"
)
// Injectors from inject.go:
func initializeDockerScanner(ctx context.Context, imageName string, layerCache cache.ImageCache, localImageCache cache.LocalImageCache, timeout time.Duration) (scanner.Scanner, func(), error) {
applier := analyzer.NewApplier(localImageCache)
detector := ospkg.Detector{}
driverFactory := library.DriverFactory{}
libraryDetector := library.NewDetector(driverFactory)
localScanner := local.NewScanner(applier, detector, libraryDetector)
dockerOption, err := types.GetDockerOption(timeout)
if err != nil {
return scanner.Scanner{}, nil, err
}
extractor, cleanup, err := docker.NewDockerExtractor(ctx, imageName, dockerOption)
if err != nil {
return scanner.Scanner{}, nil, err
}
config := analyzer.New(extractor, layerCache)
scannerScanner := scanner.NewScanner(localScanner, config)
return scannerScanner, func() {
cleanup()
}, nil
}
func initializeArchiveScanner(ctx context.Context, filePath string, layerCache cache.ImageCache, localImageCache cache.LocalImageCache, timeout time.Duration) (scanner.Scanner, error) {
applier := analyzer.NewApplier(localImageCache)
detector := ospkg.Detector{}
driverFactory := library.DriverFactory{}
libraryDetector := library.NewDetector(driverFactory)
localScanner := local.NewScanner(applier, detector, libraryDetector)
extractor, err := docker.NewArchiveImageExtractor(filePath)
if err != nil {
return scanner.Scanner{}, err
}
config := analyzer.New(extractor, layerCache)
scannerScanner := scanner.NewScanner(localScanner, config)
return scannerScanner, nil
}
func initializeVulnerabilityClient() vulnerability.Client {
config := db.Config{}
client := vulnerability.NewClient(config)
return client
}

16
pkg/cache/remote.go vendored
View File

@@ -20,32 +20,32 @@ type RemoteCache struct {
type RemoteURL string
func NewRemoteCache(url RemoteURL, customHeaders http.Header) cache.ImageCache {
func NewRemoteCache(url RemoteURL, customHeaders http.Header) cache.ArtifactCache {
ctx := client.WithCustomHeaders(context.Background(), customHeaders)
c := rpcCache.NewCacheProtobufClient(string(url), &http.Client{})
return &RemoteCache{ctx: ctx, client: c}
}
func (c RemoteCache) PutImage(imageID string, imageInfo types.ImageInfo) error {
_, err := c.client.PutImage(c.ctx, rpc.ConvertToRpcImageInfo(imageID, imageInfo))
func (c RemoteCache) PutArtifact(imageID string, imageInfo types.ArtifactInfo) error {
_, err := c.client.PutArtifact(c.ctx, rpc.ConvertToRpcArtifactInfo(imageID, imageInfo))
if err != nil {
return xerrors.Errorf("unable to store cache on the server: %w", err)
}
return nil
}
func (c RemoteCache) PutLayer(diffID string, layerInfo types.LayerInfo) error {
_, err := c.client.PutLayer(c.ctx, rpc.ConvertToRpcLayerInfo(diffID, layerInfo))
func (c RemoteCache) PutBlob(diffID string, layerInfo types.BlobInfo) error {
_, err := c.client.PutBlob(c.ctx, rpc.ConvertToRpcBlobInfo(diffID, layerInfo))
if err != nil {
return xerrors.Errorf("unable to store cache on the server: %w", err)
}
return nil
}
func (c RemoteCache) MissingLayers(imageID string, layerIDs []string) (bool, []string, error) {
layers, err := c.client.MissingLayers(c.ctx, rpc.ConvertToMissingLayersRequest(imageID, layerIDs))
func (c RemoteCache) MissingBlobs(imageID string, layerIDs []string) (bool, []string, error) {
layers, err := c.client.MissingBlobs(c.ctx, rpc.ConvertToMissingBlobsRequest(imageID, layerIDs))
if err != nil {
return false, nil, xerrors.Errorf("unable to fetch missing layers: %w", err)
}
return layers.MissingImage, layers.MissingLayerIds, nil
return layers.MissingArtifact, layers.MissingBlobIds, nil
}

View File

@@ -25,29 +25,29 @@ type mockCacheServer struct {
cache fcache.Cache
}
func (s *mockCacheServer) PutImage(_ context.Context, in *rpcCache.PutImageRequest) (*google_protobuf.Empty, error) {
if strings.Contains(in.ImageId, "invalid") {
func (s *mockCacheServer) PutArtifact(_ context.Context, in *rpcCache.PutArtifactRequest) (*google_protobuf.Empty, error) {
if strings.Contains(in.ArtifactId, "invalid") {
return &google_protobuf.Empty{}, xerrors.New("invalid image ID")
}
return &google_protobuf.Empty{}, nil
}
func (s *mockCacheServer) PutLayer(_ context.Context, in *rpcCache.PutLayerRequest) (*google_protobuf.Empty, error) {
func (s *mockCacheServer) PutBlob(_ context.Context, in *rpcCache.PutBlobRequest) (*google_protobuf.Empty, error) {
if strings.Contains(in.DiffId, "invalid") {
return &google_protobuf.Empty{}, xerrors.New("invalid layer ID")
}
return &google_protobuf.Empty{}, nil
}
func (s *mockCacheServer) MissingLayers(_ context.Context, in *rpcCache.MissingLayersRequest) (*rpcCache.MissingLayersResponse, error) {
func (s *mockCacheServer) MissingBlobs(_ context.Context, in *rpcCache.MissingBlobsRequest) (*rpcCache.MissingBlobsResponse, error) {
var layerIDs []string
for _, layerID := range in.LayerIds[:len(in.LayerIds)-1] {
for _, layerID := range in.BlobIds[:len(in.BlobIds)-1] {
if strings.Contains(layerID, "invalid") {
return nil, xerrors.New("invalid layer ID")
}
layerIDs = append(layerIDs, layerID)
}
return &rpcCache.MissingLayersResponse{MissingImage: true, MissingLayerIds: layerIDs}, nil
return &rpcCache.MissingBlobsResponse{MissingArtifact: true, MissingBlobIds: layerIDs}, nil
}
func withToken(base http.Handler, token, tokenHeader string) http.Handler {
@@ -60,7 +60,7 @@ func withToken(base http.Handler, token, tokenHeader string) http.Handler {
})
}
func TestRemoteCache_PutImage(t *testing.T) {
func TestRemoteCache_PutArtifact(t *testing.T) {
mux := http.NewServeMux()
layerHandler := rpcCache.NewCacheServer(new(mockCacheServer), nil)
mux.Handle(rpcCache.CachePathPrefix, withToken(layerHandler, "valid-token", "Trivy-Token"))
@@ -68,7 +68,7 @@ func TestRemoteCache_PutImage(t *testing.T) {
type args struct {
imageID string
imageInfo types.ImageInfo
imageInfo types.ArtifactInfo
customHeaders http.Header
}
tests := []struct {
@@ -80,7 +80,7 @@ func TestRemoteCache_PutImage(t *testing.T) {
name: "happy path",
args: args{
imageID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
imageInfo: types.ImageInfo{
imageInfo: types.ArtifactInfo{
SchemaVersion: 1,
Architecture: "amd64",
Created: time.Time{},
@@ -102,7 +102,7 @@ func TestRemoteCache_PutImage(t *testing.T) {
name: "sad path",
args: args{
imageID: "sha256:invalid",
imageInfo: types.ImageInfo{
imageInfo: types.ArtifactInfo{
SchemaVersion: 1,
Architecture: "amd64",
Created: time.Time{},
@@ -135,7 +135,7 @@ func TestRemoteCache_PutImage(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := cache.NewRemoteCache(cache.RemoteURL(ts.URL), tt.args.customHeaders)
err := c.PutImage(tt.args.imageID, tt.args.imageInfo)
err := c.PutArtifact(tt.args.imageID, tt.args.imageInfo)
if tt.wantErr != "" {
require.NotNil(t, err, tt.name)
assert.Contains(t, err.Error(), tt.wantErr, tt.name)
@@ -147,7 +147,7 @@ func TestRemoteCache_PutImage(t *testing.T) {
}
}
func TestRemoteCache_PutLayer(t *testing.T) {
func TestRemoteCache_PutBlob(t *testing.T) {
mux := http.NewServeMux()
layerHandler := rpcCache.NewCacheServer(new(mockCacheServer), nil)
mux.Handle(rpcCache.CachePathPrefix, withToken(layerHandler, "valid-token", "Trivy-Token"))
@@ -155,7 +155,7 @@ func TestRemoteCache_PutLayer(t *testing.T) {
type args struct {
diffID string
layerInfo types.LayerInfo
layerInfo types.BlobInfo
customHeaders http.Header
}
tests := []struct {
@@ -196,7 +196,7 @@ func TestRemoteCache_PutLayer(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := cache.NewRemoteCache(cache.RemoteURL(ts.URL), tt.args.customHeaders)
err := c.PutLayer(tt.args.diffID, tt.args.layerInfo)
err := c.PutBlob(tt.args.diffID, tt.args.layerInfo)
if tt.wantErr != "" {
require.NotNil(t, err, tt.name)
assert.Contains(t, err.Error(), tt.wantErr, tt.name)
@@ -208,7 +208,7 @@ func TestRemoteCache_PutLayer(t *testing.T) {
}
}
func TestRemoteCache_MissingLayers(t *testing.T) {
func TestRemoteCache_MissingBlobs(t *testing.T) {
mux := http.NewServeMux()
layerHandler := rpcCache.NewCacheServer(new(mockCacheServer), nil)
mux.Handle(rpcCache.CachePathPrefix, withToken(layerHandler, "valid-token", "Trivy-Token"))
@@ -274,7 +274,7 @@ func TestRemoteCache_MissingLayers(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := cache.NewRemoteCache(cache.RemoteURL(ts.URL), tt.args.customHeaders)
gotMissingImage, gotMissingLayerIDs, err := c.MissingLayers(tt.args.imageID, tt.args.layerIDs)
gotMissingImage, gotMissingLayerIDs, err := c.MissingBlobs(tt.args.imageID, tt.args.layerIDs)
if tt.wantErr != "" {
require.NotNil(t, err, tt.name)
assert.Contains(t, err.Error(), tt.wantErr, tt.name)

View File

@@ -45,9 +45,9 @@ func (s Scanner) Scan(target string, imageID string, layerIDs []string, options
err := r.Retry(func() error {
var err error
res, err = s.client.Scan(ctx, &rpc.ScanRequest{
Target: target,
ImageId: imageID,
LayerIds: layerIDs,
Target: target,
ArtifactId: imageID,
BlobIds: layerIDs,
Options: &rpc.ScanOptions{
VulnType: options.VulnType,
},

View File

@@ -124,9 +124,9 @@ func TestScanner_Scan(t *testing.T) {
Args: scanArgs{
CtxAnything: true,
Request: &scanner.ScanRequest{
Target: "alpine:3.11",
ImageId: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
LayerIds: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
Target: "alpine:3.11",
ArtifactId: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
BlobIds: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
Options: &scanner.ScanOptions{
VulnType: []string{"os"},
},
@@ -211,9 +211,9 @@ func TestScanner_Scan(t *testing.T) {
Args: scanArgs{
CtxAnything: true,
Request: &scanner.ScanRequest{
Target: "alpine:3.11",
ImageId: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
LayerIds: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
Target: "alpine:3.11",
ArtifactId: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
BlobIds: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
Options: &scanner.ScanOptions{
VulnType: []string{"os"},
},

View File

@@ -188,28 +188,28 @@ func ConvertFromRpcApplications(rpcApps []*common.Application) []ftypes.Applicat
return apps
}
func ConvertFromRpcPutImageRequest(req *cache.PutImageRequest) ftypes.ImageInfo {
created, _ := ptypes.Timestamp(req.ImageInfo.Created)
return ftypes.ImageInfo{
SchemaVersion: int(req.ImageInfo.SchemaVersion),
Architecture: req.ImageInfo.Architecture,
func ConvertFromRpcPutArtifactRequest(req *cache.PutArtifactRequest) ftypes.ArtifactInfo {
created, _ := ptypes.Timestamp(req.ArtifactInfo.Created)
return ftypes.ArtifactInfo{
SchemaVersion: int(req.ArtifactInfo.SchemaVersion),
Architecture: req.ArtifactInfo.Architecture,
Created: created,
DockerVersion: req.ImageInfo.DockerVersion,
OS: req.ImageInfo.Os,
HistoryPackages: ConvertFromRpcPkgs(req.ImageInfo.HistoryPackages),
DockerVersion: req.ArtifactInfo.DockerVersion,
OS: req.ArtifactInfo.Os,
HistoryPackages: ConvertFromRpcPkgs(req.ArtifactInfo.HistoryPackages),
}
}
func ConvertFromRpcPutLayerRequest(req *cache.PutLayerRequest) ftypes.LayerInfo {
return ftypes.LayerInfo{
SchemaVersion: int(req.LayerInfo.SchemaVersion),
Digest: req.LayerInfo.Digest,
DiffID: req.LayerInfo.DiffId,
OS: ConvertFromRpcOS(req.LayerInfo.Os),
PackageInfos: ConvertFromRpcPackageInfos(req.LayerInfo.PackageInfos),
Applications: ConvertFromRpcApplications(req.LayerInfo.Applications),
OpaqueDirs: req.LayerInfo.OpaqueDirs,
WhiteoutFiles: req.LayerInfo.WhiteoutFiles,
func ConvertFromRpcPutBlobRequest(req *cache.PutBlobRequest) ftypes.BlobInfo {
return ftypes.BlobInfo{
SchemaVersion: int(req.BlobInfo.SchemaVersion),
Digest: req.BlobInfo.Digest,
DiffID: req.BlobInfo.DiffId,
OS: ConvertFromRpcOS(req.BlobInfo.Os),
PackageInfos: ConvertFromRpcPackageInfos(req.BlobInfo.PackageInfos),
Applications: ConvertFromRpcApplications(req.BlobInfo.Applications),
OpaqueDirs: req.BlobInfo.OpaqueDirs,
WhiteoutFiles: req.BlobInfo.WhiteoutFiles,
}
}
@@ -223,15 +223,15 @@ func ConvertToRpcOS(fos *ftypes.OS) *common.OS {
}
}
func ConvertToRpcImageInfo(imageID string, imageInfo ftypes.ImageInfo) *cache.PutImageRequest {
func ConvertToRpcArtifactInfo(imageID string, imageInfo ftypes.ArtifactInfo) *cache.PutArtifactRequest {
t, err := ptypes.TimestampProto(imageInfo.Created)
if err != nil {
log.Logger.Warnf("invalid timestamp: %s", err)
}
return &cache.PutImageRequest{
ImageId: imageID,
ImageInfo: &cache.ImageInfo{
return &cache.PutArtifactRequest{
ArtifactId: imageID,
ArtifactInfo: &cache.ArtifactInfo{
SchemaVersion: int32(imageInfo.SchemaVersion),
Architecture: imageInfo.Architecture,
Created: t,
@@ -242,7 +242,7 @@ func ConvertToRpcImageInfo(imageID string, imageInfo ftypes.ImageInfo) *cache.Pu
}
}
func ConvertToRpcLayerInfo(diffID string, layerInfo ftypes.LayerInfo) *cache.PutLayerRequest {
func ConvertToRpcBlobInfo(diffID string, layerInfo ftypes.BlobInfo) *cache.PutBlobRequest {
var packageInfos []*common.PackageInfo
for _, pkgInfo := range layerInfo.PackageInfos {
packageInfos = append(packageInfos, &common.PackageInfo{
@@ -268,10 +268,10 @@ func ConvertToRpcLayerInfo(diffID string, layerInfo ftypes.LayerInfo) *cache.Put
})
}
return &cache.PutLayerRequest{
return &cache.PutBlobRequest{
DiffId: diffID,
LayerInfo: &cache.LayerInfo{
SchemaVersion: ftypes.LayerJSONSchemaVersion,
BlobInfo: &cache.BlobInfo{
SchemaVersion: ftypes.BlobJSONSchemaVersion,
Digest: layerInfo.Digest,
DiffId: layerInfo.DiffID,
Os: ConvertToRpcOS(layerInfo.OS),
@@ -283,10 +283,10 @@ func ConvertToRpcLayerInfo(diffID string, layerInfo ftypes.LayerInfo) *cache.Put
}
}
func ConvertToMissingLayersRequest(imageID string, layerIDs []string) *cache.MissingLayersRequest {
return &cache.MissingLayersRequest{
ImageId: imageID,
LayerIds: layerIDs,
func ConvertToMissingBlobsRequest(imageID string, layerIDs []string) *cache.MissingBlobsRequest {
return &cache.MissingBlobsRequest{
ArtifactId: imageID,
BlobIds: layerIDs,
}
}

View File

@@ -9,7 +9,7 @@ import (
"github.com/google/wire"
)
func initializeScanServer(localLayerCache cache.LocalImageCache) *ScanServer {
func initializeScanServer(localArtifactCache cache.LocalArtifactCache) *ScanServer {
wire.Build(ScanSuperSet)
return &ScanServer{}
}

View File

@@ -36,7 +36,7 @@ func NewScanServer(s scanner.Driver, vulnClient vulnerability.Operation) *ScanSe
func (s *ScanServer) Scan(_ context.Context, in *rpcScanner.ScanRequest) (*rpcScanner.ScanResponse, error) {
options := types.ScanOptions{VulnType: in.Options.VulnType}
results, os, eosl, err := s.localScanner.Scan(in.Target, in.ImageId, in.LayerIds, options)
results, os, eosl, err := s.localScanner.Scan(in.Target, in.ArtifactId, in.BlobIds, options)
if err != nil {
return nil, xerrors.Errorf("failed scan, %s: %w", in.Target, err)
}
@@ -55,40 +55,40 @@ func NewCacheServer(c cache.Cache) *CacheServer {
return &CacheServer{cache: c}
}
func (s *CacheServer) PutImage(_ context.Context, in *rpcCache.PutImageRequest) (*google_protobuf.Empty, error) {
if in.ImageInfo == nil {
func (s *CacheServer) PutArtifact(_ context.Context, in *rpcCache.PutArtifactRequest) (*google_protobuf.Empty, error) {
if in.ArtifactInfo == nil {
return nil, xerrors.Errorf("empty image info")
}
imageInfo := rpc.ConvertFromRpcPutImageRequest(in)
if err := s.cache.PutImage(in.ImageId, imageInfo); err != nil {
imageInfo := rpc.ConvertFromRpcPutArtifactRequest(in)
if err := s.cache.PutArtifact(in.ArtifactId, imageInfo); err != nil {
return nil, xerrors.Errorf("unable to store image info in cache: %w", err)
}
return &google_protobuf.Empty{}, nil
}
func (s *CacheServer) PutLayer(_ context.Context, in *rpcCache.PutLayerRequest) (*google_protobuf.Empty, error) {
if in.LayerInfo == nil {
func (s *CacheServer) PutBlob(_ context.Context, in *rpcCache.PutBlobRequest) (*google_protobuf.Empty, error) {
if in.BlobInfo == nil {
return nil, xerrors.Errorf("empty layer info")
}
layerInfo := rpc.ConvertFromRpcPutLayerRequest(in)
if err := s.cache.PutLayer(in.DiffId, layerInfo); err != nil {
layerInfo := rpc.ConvertFromRpcPutBlobRequest(in)
if err := s.cache.PutBlob(in.DiffId, layerInfo); err != nil {
return nil, xerrors.Errorf("unable to store layer info in cache: %w", err)
}
return &google_protobuf.Empty{}, nil
}
func (s *CacheServer) MissingLayers(_ context.Context, in *rpcCache.MissingLayersRequest) (*rpcCache.MissingLayersResponse, error) {
func (s *CacheServer) MissingBlobs(_ context.Context, in *rpcCache.MissingBlobsRequest) (*rpcCache.MissingBlobsResponse, error) {
var layerIDs []string
for _, layerID := range in.LayerIds {
l, err := s.cache.GetLayer(layerID)
if err != nil || l.SchemaVersion != ftypes.LayerJSONSchemaVersion {
layerIDs = append(layerIDs, layerID)
for _, blobID := range in.BlobIds {
l, err := s.cache.GetBlob(blobID)
if err != nil || l.SchemaVersion != ftypes.BlobJSONSchemaVersion {
layerIDs = append(layerIDs, blobID)
}
}
var missingImage bool
img, err := s.cache.GetImage(in.ImageId)
if err != nil || img.SchemaVersion != ftypes.ImageJSONSchemaVersion {
img, err := s.cache.GetArtifact(in.ArtifactId)
if err != nil || img.SchemaVersion != ftypes.ArtifactJSONSchemaVersion {
missingImage = true
}
return &rpcCache.MissingLayersResponse{MissingImage: missingImage, MissingLayerIds: layerIDs}, nil
return &rpcCache.MissingBlobsResponse{MissingArtifact: missingImage, MissingBlobIds: layerIDs}, nil
}

View File

@@ -6,19 +6,16 @@ import (
"testing"
"time"
deptypes "github.com/aquasecurity/go-dep-parser/pkg/types"
"github.com/golang/protobuf/ptypes/timestamp"
"github.com/golang/protobuf/ptypes"
google_protobuf "github.com/golang/protobuf/ptypes/empty"
"github.com/golang/protobuf/ptypes/timestamp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/xerrors"
"github.com/aquasecurity/fanal/cache"
ftypes "github.com/aquasecurity/fanal/types"
deptypes "github.com/aquasecurity/go-dep-parser/pkg/types"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy/pkg/report"
"github.com/aquasecurity/trivy/pkg/scanner"
@@ -30,8 +27,8 @@ import (
)
type mockCache struct {
cache.MockImageCache
cache.MockLocalImageCache
cache.MockArtifactCache
cache.MockLocalArtifactCache
}
func TestScanServer_Scan(t *testing.T) {
@@ -41,7 +38,7 @@ func TestScanServer_Scan(t *testing.T) {
tests := []struct {
name string
args args
scanExpectation scanner.ScanExpectation
scanExpectation scanner.DriverScanExpectation
fillInfoExpectation vulnerability.FillInfoExpectation
want *rpcScanner.ScanResponse
wantErr string
@@ -50,19 +47,19 @@ func TestScanServer_Scan(t *testing.T) {
name: "happy path",
args: args{
in: &rpcScanner.ScanRequest{
Target: "alpine:3.11",
ImageId: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
LayerIds: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
Options: &rpcScanner.ScanOptions{},
Target: "alpine:3.11",
ArtifactId: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
BlobIds: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
Options: &rpcScanner.ScanOptions{},
},
},
scanExpectation: scanner.ScanExpectation{
Args: scanner.ScanArgs{
scanExpectation: scanner.DriverScanExpectation{
Args: scanner.DriverScanArgs{
Target: "alpine:3.11",
ImageID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
LayerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
},
Returns: scanner.ScanReturns{
Returns: scanner.DriverScanReturns{
Results: report.Results{
{
Target: "alpine:3.11 (alpine 3.11)",
@@ -128,19 +125,19 @@ func TestScanServer_Scan(t *testing.T) {
name: "sad path: Scan returns an error",
args: args{
in: &rpcScanner.ScanRequest{
Target: "alpine:3.11",
ImageId: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
LayerIds: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
Options: &rpcScanner.ScanOptions{},
Target: "alpine:3.11",
ArtifactId: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
BlobIds: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
Options: &rpcScanner.ScanOptions{},
},
},
scanExpectation: scanner.ScanExpectation{
Args: scanner.ScanArgs{
scanExpectation: scanner.DriverScanExpectation{
Args: scanner.DriverScanArgs{
Target: "alpine:3.11",
ImageID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
LayerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
},
Returns: scanner.ScanReturns{
Returns: scanner.DriverScanReturns{
Err: errors.New("error"),
},
},
@@ -170,23 +167,23 @@ func TestScanServer_Scan(t *testing.T) {
}
}
func TestCacheServer_PutImage(t *testing.T) {
func TestCacheServer_PutArtifact(t *testing.T) {
type args struct {
in *rpcCache.PutImageRequest
in *rpcCache.PutArtifactRequest
}
tests := []struct {
name string
args args
putImage cache.ImageCachePutImageExpectation
putImage cache.ArtifactCachePutArtifactExpectation
want *google_protobuf.Empty
wantErr string
}{
{
name: "happy path",
args: args{
in: &rpcCache.PutImageRequest{
ImageId: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
ImageInfo: &rpcCache.ImageInfo{
in: &rpcCache.PutArtifactRequest{
ArtifactId: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
ArtifactInfo: &rpcCache.ArtifactInfo{
SchemaVersion: 1,
Architecture: "amd64",
Created: func() *timestamp.Timestamp {
@@ -199,10 +196,10 @@ func TestCacheServer_PutImage(t *testing.T) {
},
},
},
putImage: cache.ImageCachePutImageExpectation{
Args: cache.ImageCachePutImageArgs{
ImageID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
ImageInfo: ftypes.ImageInfo{
putImage: cache.ArtifactCachePutArtifactExpectation{
Args: cache.ArtifactCachePutArtifactArgs{
ArtifactID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
ArtifactInfo: ftypes.ArtifactInfo{
SchemaVersion: 1,
Architecture: "amd64",
Created: time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC),
@@ -216,9 +213,9 @@ func TestCacheServer_PutImage(t *testing.T) {
{
name: "sad path",
args: args{
in: &rpcCache.PutImageRequest{
ImageId: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
ImageInfo: &rpcCache.ImageInfo{
in: &rpcCache.PutArtifactRequest{
ArtifactId: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
ArtifactInfo: &rpcCache.ArtifactInfo{
SchemaVersion: 1,
Created: func() *timestamp.Timestamp {
d := time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC)
@@ -228,15 +225,15 @@ func TestCacheServer_PutImage(t *testing.T) {
},
},
},
putImage: cache.ImageCachePutImageExpectation{
Args: cache.ImageCachePutImageArgs{
ImageID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
ImageInfo: ftypes.ImageInfo{
putImage: cache.ArtifactCachePutArtifactExpectation{
Args: cache.ArtifactCachePutArtifactArgs{
ArtifactID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
ArtifactInfo: ftypes.ArtifactInfo{
SchemaVersion: 1,
Created: time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC),
},
},
Returns: cache.ImageCachePutImageReturns{
Returns: cache.ArtifactCachePutArtifactReturns{
Err: xerrors.New("error"),
},
},
@@ -245,7 +242,7 @@ func TestCacheServer_PutImage(t *testing.T) {
{
name: "sad path: empty image info",
args: args{
in: &rpcCache.PutImageRequest{},
in: &rpcCache.PutArtifactRequest{},
},
wantErr: "empty image info",
},
@@ -253,10 +250,10 @@ func TestCacheServer_PutImage(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mockCache := new(mockCache)
mockCache.ApplyPutImageExpectation(tt.putImage)
mockCache.ApplyPutArtifactExpectation(tt.putImage)
s := NewCacheServer(mockCache)
got, err := s.PutImage(context.Background(), tt.args.in)
got, err := s.PutArtifact(context.Background(), tt.args.in)
if tt.wantErr != "" {
require.NotNil(t, err, tt.name)
@@ -271,23 +268,23 @@ func TestCacheServer_PutImage(t *testing.T) {
}
}
func TestCacheServer_PutLayer(t *testing.T) {
func TestCacheServer_PutBlob(t *testing.T) {
type args struct {
in *rpcCache.PutLayerRequest
in *rpcCache.PutBlobRequest
}
tests := []struct {
name string
args args
putLayer cache.ImageCachePutLayerExpectation
putLayer cache.ArtifactCachePutBlobExpectation
want *google_protobuf.Empty
wantErr string
}{
{
name: "happy path",
args: args{
in: &rpcCache.PutLayerRequest{
in: &rpcCache.PutBlobRequest{
DiffId: "sha256:b2a1a2d80bf0c747a4f6b0ca6af5eef23f043fcdb1ed4f3a3e750aef2dc68079",
LayerInfo: &rpcCache.LayerInfo{
BlobInfo: &rpcCache.BlobInfo{
SchemaVersion: 1,
Digest: "sha256:154ad0735c360b212b167f424d33a62305770a1fcfb6363882f5c436cfbd9812",
DiffId: "sha256:b2a1a2d80bf0c747a4f6b0ca6af5eef23f043fcdb1ed4f3a3e750aef2dc68079",
@@ -345,10 +342,10 @@ func TestCacheServer_PutLayer(t *testing.T) {
},
},
},
putLayer: cache.ImageCachePutLayerExpectation{
Args: cache.ImageCachePutLayerArgs{
DiffID: "sha256:b2a1a2d80bf0c747a4f6b0ca6af5eef23f043fcdb1ed4f3a3e750aef2dc68079",
LayerInfo: ftypes.LayerInfo{
putLayer: cache.ArtifactCachePutBlobExpectation{
Args: cache.ArtifactCachePutBlobArgs{
BlobID: "sha256:b2a1a2d80bf0c747a4f6b0ca6af5eef23f043fcdb1ed4f3a3e750aef2dc68079",
BlobInfo: ftypes.BlobInfo{
SchemaVersion: 1,
Digest: "sha256:154ad0735c360b212b167f424d33a62305770a1fcfb6363882f5c436cfbd9812",
DiffID: "sha256:b2a1a2d80bf0c747a4f6b0ca6af5eef23f043fcdb1ed4f3a3e750aef2dc68079",
@@ -415,18 +412,18 @@ func TestCacheServer_PutLayer(t *testing.T) {
{
name: "sad path",
args: args{
in: &rpcCache.PutLayerRequest{
LayerInfo: &rpcCache.LayerInfo{
in: &rpcCache.PutBlobRequest{
BlobInfo: &rpcCache.BlobInfo{
SchemaVersion: 1,
},
},
},
putLayer: cache.ImageCachePutLayerExpectation{
Args: cache.ImageCachePutLayerArgs{
DiffIDAnything: true,
LayerInfoAnything: true,
putLayer: cache.ArtifactCachePutBlobExpectation{
Args: cache.ArtifactCachePutBlobArgs{
BlobIDAnything: true,
BlobInfoAnything: true,
},
Returns: cache.ImageCachePutLayerReturns{
Returns: cache.ArtifactCachePutBlobReturns{
Err: xerrors.New("error"),
},
},
@@ -435,14 +432,14 @@ func TestCacheServer_PutLayer(t *testing.T) {
{
name: "sad path: empty layer info",
args: args{
in: &rpcCache.PutLayerRequest{},
in: &rpcCache.PutBlobRequest{},
},
putLayer: cache.ImageCachePutLayerExpectation{
Args: cache.ImageCachePutLayerArgs{
DiffIDAnything: true,
LayerInfoAnything: true,
putLayer: cache.ArtifactCachePutBlobExpectation{
Args: cache.ArtifactCachePutBlobArgs{
BlobIDAnything: true,
BlobInfoAnything: true,
},
Returns: cache.ImageCachePutLayerReturns{
Returns: cache.ArtifactCachePutBlobReturns{
Err: xerrors.New("error"),
},
},
@@ -452,10 +449,10 @@ func TestCacheServer_PutLayer(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mockCache := new(mockCache)
mockCache.ApplyPutLayerExpectation(tt.putLayer)
mockCache.ApplyPutBlobExpectation(tt.putLayer)
s := NewCacheServer(mockCache)
got, err := s.PutLayer(context.Background(), tt.args.in)
got, err := s.PutBlob(context.Background(), tt.args.in)
if tt.wantErr != "" {
require.NotNil(t, err, tt.name)
@@ -470,113 +467,113 @@ func TestCacheServer_PutLayer(t *testing.T) {
}
}
func TestCacheServer_MissingLayers(t *testing.T) {
func TestCacheServer_MissingBlobs(t *testing.T) {
type args struct {
ctx context.Context
in *rpcCache.MissingLayersRequest
in *rpcCache.MissingBlobsRequest
}
tests := []struct {
name string
args args
getLayerExpectations []cache.LocalImageCacheGetLayerExpectation
getImageExpectations []cache.LocalImageCacheGetImageExpectation
want *rpcCache.MissingLayersResponse
getLayerExpectations []cache.LocalArtifactCacheGetBlobExpectation
getImageExpectations []cache.LocalArtifactCacheGetArtifactExpectation
want *rpcCache.MissingBlobsResponse
wantErr string
}{
{
name: "happy path",
args: args{
in: &rpcCache.MissingLayersRequest{
ImageId: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
LayerIds: []string{
in: &rpcCache.MissingBlobsRequest{
ArtifactId: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
BlobIds: []string{
"sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
"sha256:dffd9992ca398466a663c87c92cfea2a2db0ae0cf33fcb99da60eec52addbfc5",
},
},
},
getLayerExpectations: []cache.LocalImageCacheGetLayerExpectation{
getLayerExpectations: []cache.LocalArtifactCacheGetBlobExpectation{
{
Args: cache.LocalImageCacheGetLayerArgs{
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
Args: cache.LocalArtifactCacheGetBlobArgs{
BlobID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
},
Returns: cache.LocalImageCacheGetLayerReturns{
LayerInfo: ftypes.LayerInfo{},
Returns: cache.LocalArtifactCacheGetBlobReturns{
BlobInfo: ftypes.BlobInfo{},
},
},
{
Args: cache.LocalImageCacheGetLayerArgs{
DiffID: "sha256:dffd9992ca398466a663c87c92cfea2a2db0ae0cf33fcb99da60eec52addbfc5",
Args: cache.LocalArtifactCacheGetBlobArgs{
BlobID: "sha256:dffd9992ca398466a663c87c92cfea2a2db0ae0cf33fcb99da60eec52addbfc5",
},
Returns: cache.LocalImageCacheGetLayerReturns{
LayerInfo: ftypes.LayerInfo{
Returns: cache.LocalArtifactCacheGetBlobReturns{
BlobInfo: ftypes.BlobInfo{
SchemaVersion: 1,
},
},
},
},
getImageExpectations: []cache.LocalImageCacheGetImageExpectation{
getImageExpectations: []cache.LocalArtifactCacheGetArtifactExpectation{
{
Args: cache.LocalImageCacheGetImageArgs{
ImageID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
Args: cache.LocalArtifactCacheGetArtifactArgs{
ArtifactID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
},
Returns: cache.LocalImageCacheGetImageReturns{
ImageInfo: ftypes.ImageInfo{
Returns: cache.LocalArtifactCacheGetArtifactReturns{
ArtifactInfo: ftypes.ArtifactInfo{
SchemaVersion: 1,
},
},
},
},
want: &rpcCache.MissingLayersResponse{
MissingImage: false,
MissingLayerIds: []string{"sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02"},
want: &rpcCache.MissingBlobsResponse{
MissingArtifact: false,
MissingBlobIds: []string{"sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02"},
},
},
{
name: "schema version doesn't match",
args: args{
in: &rpcCache.MissingLayersRequest{
ImageId: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
LayerIds: []string{
in: &rpcCache.MissingBlobsRequest{
ArtifactId: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
BlobIds: []string{
"sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
"sha256:dffd9992ca398466a663c87c92cfea2a2db0ae0cf33fcb99da60eec52addbfc5",
},
},
},
getLayerExpectations: []cache.LocalImageCacheGetLayerExpectation{
getLayerExpectations: []cache.LocalArtifactCacheGetBlobExpectation{
{
Args: cache.LocalImageCacheGetLayerArgs{
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
Args: cache.LocalArtifactCacheGetBlobArgs{
BlobID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
},
Returns: cache.LocalImageCacheGetLayerReturns{
LayerInfo: ftypes.LayerInfo{
Returns: cache.LocalArtifactCacheGetBlobReturns{
BlobInfo: ftypes.BlobInfo{
SchemaVersion: 0,
},
},
},
{
Args: cache.LocalImageCacheGetLayerArgs{
DiffID: "sha256:dffd9992ca398466a663c87c92cfea2a2db0ae0cf33fcb99da60eec52addbfc5",
Args: cache.LocalArtifactCacheGetBlobArgs{
BlobID: "sha256:dffd9992ca398466a663c87c92cfea2a2db0ae0cf33fcb99da60eec52addbfc5",
},
Returns: cache.LocalImageCacheGetLayerReturns{
LayerInfo: ftypes.LayerInfo{
Returns: cache.LocalArtifactCacheGetBlobReturns{
BlobInfo: ftypes.BlobInfo{
SchemaVersion: -1,
},
},
},
},
getImageExpectations: []cache.LocalImageCacheGetImageExpectation{
getImageExpectations: []cache.LocalArtifactCacheGetArtifactExpectation{
{
Args: cache.LocalImageCacheGetImageArgs{
ImageID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
Args: cache.LocalArtifactCacheGetArtifactArgs{
ArtifactID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
},
Returns: cache.LocalImageCacheGetImageReturns{
ImageInfo: ftypes.ImageInfo{},
Returns: cache.LocalArtifactCacheGetArtifactReturns{
ArtifactInfo: ftypes.ArtifactInfo{},
},
},
},
want: &rpcCache.MissingLayersResponse{
MissingImage: true,
MissingLayerIds: []string{
want: &rpcCache.MissingBlobsResponse{
MissingArtifact: true,
MissingBlobIds: []string{
"sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
"sha256:dffd9992ca398466a663c87c92cfea2a2db0ae0cf33fcb99da60eec52addbfc5",
},
@@ -586,11 +583,11 @@ func TestCacheServer_MissingLayers(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mockCache := new(mockCache)
mockCache.ApplyGetLayerExpectations(tt.getLayerExpectations)
mockCache.ApplyGetImageExpectations(tt.getImageExpectations)
mockCache.ApplyGetBlobExpectations(tt.getLayerExpectations)
mockCache.ApplyGetArtifactExpectations(tt.getImageExpectations)
s := NewCacheServer(mockCache)
got, err := s.MissingLayers(tt.args.ctx, tt.args.in)
got, err := s.MissingBlobs(tt.args.ctx, tt.args.in)
if tt.wantErr != "" {
require.NotNil(t, err, tt.name)
assert.Contains(t, err.Error(), tt.wantErr, tt.name)
@@ -600,7 +597,7 @@ func TestCacheServer_MissingLayers(t *testing.T) {
}
assert.Equal(t, tt.want, got)
mockCache.MockLocalImageCache.AssertExpectations(t)
mockCache.MockLocalArtifactCache.AssertExpectations(t)
})
}
}

View File

@@ -6,7 +6,7 @@
package server
import (
"github.com/aquasecurity/fanal/analyzer"
"github.com/aquasecurity/fanal/applier"
"github.com/aquasecurity/fanal/cache"
"github.com/aquasecurity/trivy-db/pkg/db"
db2 "github.com/aquasecurity/trivy/pkg/db"
@@ -24,12 +24,12 @@ import (
// Injectors from inject.go:
func initializeScanServer(localLayerCache cache.LocalImageCache) *ScanServer {
applier := analyzer.NewApplier(localLayerCache)
func initializeScanServer(localArtifactCache cache.LocalArtifactCache) *ScanServer {
applierApplier := applier.NewApplier(localArtifactCache)
detector := ospkg.Detector{}
driverFactory := library.DriverFactory{}
libraryDetector := library.NewDetector(driverFactory)
scanner := local.NewScanner(applier, detector, libraryDetector)
scanner := local.NewScanner(applierApplier, detector, libraryDetector)
config := db.Config{}
client := vulnerability.NewClient(config)
scanServer := NewScanServer(scanner, client)

View File

@@ -2,8 +2,10 @@
package local
import mock "github.com/stretchr/testify/mock"
import types "github.com/aquasecurity/fanal/types"
import (
types "github.com/aquasecurity/fanal/types"
mock "github.com/stretchr/testify/mock"
)
// MockApplier is an autogenerated mock type for the Applier type
type MockApplier struct {
@@ -11,14 +13,14 @@ type MockApplier struct {
}
type ApplierApplyLayersArgs struct {
ImageID string
ImageIDAnything bool
LayerIDs []string
LayerIDsAnything bool
ArtifactID string
ArtifactIDAnything bool
BlobIDs []string
BlobIDsAnything bool
}
type ApplierApplyLayersReturns struct {
Detail types.ImageDetail
Detail types.ArtifactDetail
Err error
}
@@ -29,15 +31,15 @@ type ApplierApplyLayersExpectation struct {
func (_m *MockApplier) ApplyApplyLayersExpectation(e ApplierApplyLayersExpectation) {
var args []interface{}
if e.Args.ImageIDAnything {
if e.Args.ArtifactIDAnything {
args = append(args, mock.Anything)
} else {
args = append(args, e.Args.ImageID)
args = append(args, e.Args.ArtifactID)
}
if e.Args.LayerIDsAnything {
if e.Args.BlobIDsAnything {
args = append(args, mock.Anything)
} else {
args = append(args, e.Args.LayerIDs)
args = append(args, e.Args.BlobIDs)
}
_m.On("ApplyLayers", args...).Return(e.Returns.Detail, e.Returns.Err)
}
@@ -48,20 +50,20 @@ func (_m *MockApplier) ApplyApplyLayersExpectations(expectations []ApplierApplyL
}
}
// ApplyLayers provides a mock function with given fields: imageID, layerIDs
func (_m *MockApplier) ApplyLayers(imageID string, layerIDs []string) (types.ImageDetail, error) {
ret := _m.Called(imageID, layerIDs)
// ApplyLayers provides a mock function with given fields: artifactID, blobIDs
func (_m *MockApplier) ApplyLayers(artifactID string, blobIDs []string) (types.ArtifactDetail, error) {
ret := _m.Called(artifactID, blobIDs)
var r0 types.ImageDetail
if rf, ok := ret.Get(0).(func(string, []string) types.ImageDetail); ok {
r0 = rf(imageID, layerIDs)
var r0 types.ArtifactDetail
if rf, ok := ret.Get(0).(func(string, []string) types.ArtifactDetail); ok {
r0 = rf(artifactID, blobIDs)
} else {
r0 = ret.Get(0).(types.ImageDetail)
r0 = ret.Get(0).(types.ArtifactDetail)
}
var r1 error
if rf, ok := ret.Get(1).(func(string, []string) error); ok {
r1 = rf(imageID, layerIDs)
r1 = rf(artifactID, blobIDs)
} else {
r1 = ret.Error(1)
}

View File

@@ -19,13 +19,15 @@ import (
_ "github.com/aquasecurity/fanal/analyzer/library/yarn"
_ "github.com/aquasecurity/fanal/analyzer/os/alpine"
_ "github.com/aquasecurity/fanal/analyzer/os/amazonlinux"
_ "github.com/aquasecurity/fanal/analyzer/os/debianbase"
_ "github.com/aquasecurity/fanal/analyzer/os/debian"
_ "github.com/aquasecurity/fanal/analyzer/os/photon"
_ "github.com/aquasecurity/fanal/analyzer/os/redhatbase"
_ "github.com/aquasecurity/fanal/analyzer/os/suse"
_ "github.com/aquasecurity/fanal/analyzer/os/ubuntu"
_ "github.com/aquasecurity/fanal/analyzer/pkg/apk"
_ "github.com/aquasecurity/fanal/analyzer/pkg/dpkg"
_ "github.com/aquasecurity/fanal/analyzer/pkg/rpmcmd"
"github.com/aquasecurity/fanal/applier"
ftypes "github.com/aquasecurity/fanal/types"
libDetector "github.com/aquasecurity/trivy/pkg/detector/library"
ospkgDetector "github.com/aquasecurity/trivy/pkg/detector/ospkg"
@@ -36,8 +38,8 @@ import (
)
var SuperSet = wire.NewSet(
analyzer.NewApplier,
wire.Bind(new(Applier), new(analyzer.Applier)),
applier.NewApplier,
wire.Bind(new(Applier), new(applier.Applier)),
ospkgDetector.SuperSet,
wire.Bind(new(OspkgDetector), new(ospkgDetector.Detector)),
libDetector.SuperSet,
@@ -46,7 +48,7 @@ var SuperSet = wire.NewSet(
)
type Applier interface {
ApplyLayers(imageID string, layerIDs []string) (detail ftypes.ImageDetail, err error)
ApplyLayers(artifactID string, blobIDs []string) (detail ftypes.ArtifactDetail, err error)
}
type OspkgDetector interface {
@@ -72,7 +74,7 @@ func (s Scanner) Scan(target string, imageID string, layerIDs []string, options
if err != nil {
switch err {
case analyzer.ErrUnknownOS:
log.Logger.Warn("This OS is not supported and vulnerabilities in OS packages are not detected.")
log.Logger.Warn("OS is not detected and vulnerabilities in OS packages are not detected.")
case analyzer.ErrNoPkgsDetected:
log.Logger.Warn("No OS package is detected. Make sure you haven't deleted any files that contain information about the installed packages.")
log.Logger.Warn(`e.g. files under "/lib/apk/db/", "/var/lib/dpkg/" and "/var/lib/rpm"`)

View File

@@ -43,10 +43,10 @@ func TestScanner_Scan(t *testing.T) {
},
applyLayersExpectation: ApplierApplyLayersExpectation{
Args: ApplierApplyLayersArgs{
LayerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
BlobIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
},
Returns: ApplierApplyLayersReturns{
Detail: ftypes.ImageDetail{
Detail: ftypes.ArtifactDetail{
OS: &ftypes.OS{
Family: "alpine",
Name: "3.11",
@@ -182,10 +182,10 @@ func TestScanner_Scan(t *testing.T) {
},
applyLayersExpectation: ApplierApplyLayersExpectation{
Args: ApplierApplyLayersArgs{
LayerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
BlobIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
},
Returns: ApplierApplyLayersReturns{
Detail: ftypes.ImageDetail{
Detail: ftypes.ArtifactDetail{
OS: &ftypes.OS{},
Applications: []ftypes.Application{
{
@@ -260,10 +260,10 @@ func TestScanner_Scan(t *testing.T) {
},
applyLayersExpectation: ApplierApplyLayersExpectation{
Args: ApplierApplyLayersArgs{
LayerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
BlobIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
},
Returns: ApplierApplyLayersReturns{
Detail: ftypes.ImageDetail{
Detail: ftypes.ArtifactDetail{
OS: &ftypes.OS{
Family: "alpine",
Name: "3.11",
@@ -360,10 +360,10 @@ func TestScanner_Scan(t *testing.T) {
},
applyLayersExpectation: ApplierApplyLayersExpectation{
Args: ApplierApplyLayersArgs{
LayerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
BlobIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
},
Returns: ApplierApplyLayersReturns{
Detail: ftypes.ImageDetail{
Detail: ftypes.ArtifactDetail{
OS: &ftypes.OS{
Family: "fedora",
Name: "27",
@@ -455,10 +455,10 @@ func TestScanner_Scan(t *testing.T) {
},
applyLayersExpectation: ApplierApplyLayersExpectation{
Args: ApplierApplyLayersArgs{
LayerIDs: []string{"sha256:a6d503001157aedc826853f9b67f26d35966221b158bff03849868ae4a821116"},
BlobIDs: []string{"sha256:a6d503001157aedc826853f9b67f26d35966221b158bff03849868ae4a821116"},
},
Returns: ApplierApplyLayersReturns{
Detail: ftypes.ImageDetail{
Detail: ftypes.ArtifactDetail{
OS: nil,
},
Err: analyzer.ErrUnknownOS,
@@ -476,10 +476,10 @@ func TestScanner_Scan(t *testing.T) {
},
applyLayersExpectation: ApplierApplyLayersExpectation{
Args: ApplierApplyLayersArgs{
LayerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
BlobIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
},
Returns: ApplierApplyLayersReturns{
Detail: ftypes.ImageDetail{
Detail: ftypes.ArtifactDetail{
OS: &ftypes.OS{
Family: "alpine",
Name: "3.11",
@@ -616,7 +616,7 @@ func TestScanner_Scan(t *testing.T) {
},
applyLayersExpectation: ApplierApplyLayersExpectation{
Args: ApplierApplyLayersArgs{
LayerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
BlobIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
},
Returns: ApplierApplyLayersReturns{
Err: errors.New("error"),
@@ -633,10 +633,10 @@ func TestScanner_Scan(t *testing.T) {
},
applyLayersExpectation: ApplierApplyLayersExpectation{
Args: ApplierApplyLayersArgs{
LayerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
BlobIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
},
Returns: ApplierApplyLayersReturns{
Detail: ftypes.ImageDetail{
Detail: ftypes.ArtifactDetail{
OS: &ftypes.OS{
Family: "alpine",
Name: "3.11",
@@ -684,10 +684,10 @@ func TestScanner_Scan(t *testing.T) {
},
applyLayersExpectation: ApplierApplyLayersExpectation{
Args: ApplierApplyLayersArgs{
LayerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
BlobIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
},
Returns: ApplierApplyLayersReturns{
Detail: ftypes.ImageDetail{
Detail: ftypes.ArtifactDetail{
OS: &ftypes.OS{
Family: "alpine",
Name: "3.11",

View File

@@ -1,64 +0,0 @@
// Code generated by mockery v1.0.0. DO NOT EDIT.
package scanner
import context "context"
import mock "github.com/stretchr/testify/mock"
import types "github.com/aquasecurity/fanal/types"
// MockAnalyzer is an autogenerated mock type for the Analyzer type
type MockAnalyzer struct {
mock.Mock
}
type AnalyzerAnalyzeArgs struct {
Ctx context.Context
CtxAnything bool
}
type AnalyzerAnalyzeReturns struct {
Info types.ImageReference
Err error
}
type AnalyzerAnalyzeExpectation struct {
Args AnalyzerAnalyzeArgs
Returns AnalyzerAnalyzeReturns
}
func (_m *MockAnalyzer) ApplyAnalyzeExpectation(e AnalyzerAnalyzeExpectation) {
var args []interface{}
if e.Args.CtxAnything {
args = append(args, mock.Anything)
} else {
args = append(args, e.Args.Ctx)
}
_m.On("Analyze", args...).Return(e.Returns.Info, e.Returns.Err)
}
func (_m *MockAnalyzer) ApplyAnalyzeExpectations(expectations []AnalyzerAnalyzeExpectation) {
for _, e := range expectations {
_m.ApplyAnalyzeExpectation(e)
}
}
// Analyze provides a mock function with given fields: ctx
func (_m *MockAnalyzer) Analyze(ctx context.Context) (types.ImageReference, error) {
ret := _m.Called(ctx)
var r0 types.ImageReference
if rf, ok := ret.Get(0).(func(context.Context) types.ImageReference); ok {
r0 = rf(ctx)
} else {
r0 = ret.Get(0).(types.ImageReference)
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context) error); ok {
r1 = rf(ctx)
} else {
r1 = ret.Error(1)
}
return r0, r1
}

View File

@@ -2,17 +2,21 @@
package scanner
import fanaltypes "github.com/aquasecurity/fanal/types"
import mock "github.com/stretchr/testify/mock"
import report "github.com/aquasecurity/trivy/pkg/report"
import types "github.com/aquasecurity/trivy/pkg/types"
import (
fanaltypes "github.com/aquasecurity/fanal/types"
mock "github.com/stretchr/testify/mock"
report "github.com/aquasecurity/trivy/pkg/report"
types "github.com/aquasecurity/trivy/pkg/types"
)
// MockDriver is an autogenerated mock type for the Driver type
type MockDriver struct {
mock.Mock
}
type ScanArgs struct {
type DriverScanArgs struct {
Target string
TargetAnything bool
ImageID string
@@ -23,19 +27,19 @@ type ScanArgs struct {
OptionsAnything bool
}
type ScanReturns struct {
type DriverScanReturns struct {
Results report.Results
OsFound *fanaltypes.OS
Eols bool
Err error
}
type ScanExpectation struct {
Args ScanArgs
Returns ScanReturns
type DriverScanExpectation struct {
Args DriverScanArgs
Returns DriverScanReturns
}
func (_m *MockDriver) ApplyScanExpectation(e ScanExpectation) {
func (_m *MockDriver) ApplyScanExpectation(e DriverScanExpectation) {
var args []interface{}
if e.Args.TargetAnything {
args = append(args, mock.Anything)
@@ -60,7 +64,7 @@ func (_m *MockDriver) ApplyScanExpectation(e ScanExpectation) {
_m.On("Scan", args...).Return(e.Returns.Results, e.Returns.OsFound, e.Returns.Eols, e.Returns.Err)
}
func (_m *MockDriver) ApplyScanExpectations(expectations []ScanExpectation) {
func (_m *MockDriver) ApplyScanExpectations(expectations []DriverScanExpectation) {
for _, e := range expectations {
_m.ApplyScanExpectation(e)
}

View File

@@ -6,9 +6,11 @@ import (
"github.com/google/wire"
"golang.org/x/xerrors"
"github.com/aquasecurity/fanal/analyzer"
"github.com/aquasecurity/fanal/extractor"
"github.com/aquasecurity/fanal/extractor/docker"
"github.com/aquasecurity/fanal/artifact"
aimage "github.com/aquasecurity/fanal/artifact/image"
flocal "github.com/aquasecurity/fanal/artifact/local"
"github.com/aquasecurity/fanal/artifact/remote"
"github.com/aquasecurity/fanal/image"
ftypes "github.com/aquasecurity/fanal/types"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/report"
@@ -19,8 +21,6 @@ import (
// StandaloneSuperSet is used in the standalone mode
var StandaloneSuperSet = wire.NewSet(
analyzer.New,
wire.Bind(new(Analyzer), new(analyzer.Config)),
local.SuperSet,
wire.Bind(new(Driver), new(local.Scanner)),
NewScanner,
@@ -28,21 +28,30 @@ var StandaloneSuperSet = wire.NewSet(
var StandaloneDockerSet = wire.NewSet(
types.GetDockerOption,
docker.NewDockerExtractor,
wire.Bind(new(extractor.Extractor), new(docker.Extractor)),
image.NewDockerImage,
aimage.NewArtifact,
StandaloneSuperSet,
)
var StandaloneArchiveSet = wire.NewSet(
docker.NewArchiveImageExtractor,
wire.Bind(new(extractor.Extractor), new(docker.Extractor)),
image.NewArchiveImage,
aimage.NewArtifact,
StandaloneSuperSet,
)
var StandaloneFilesystemSet = wire.NewSet(
flocal.NewArtifact,
StandaloneSuperSet,
)
var StandaloneRepositorySet = wire.NewSet(
remote.NewArtifact,
StandaloneSuperSet,
)
// RemoteSuperSet is used in the client mode
var RemoteSuperSet = wire.NewSet(
analyzer.New,
wire.Bind(new(Analyzer), new(analyzer.Config)),
aimage.NewArtifact,
client.SuperSet,
wire.Bind(new(Driver), new(client.Scanner)),
NewScanner,
@@ -50,45 +59,38 @@ var RemoteSuperSet = wire.NewSet(
var RemoteDockerSet = wire.NewSet(
types.GetDockerOption,
docker.NewDockerExtractor,
wire.Bind(new(extractor.Extractor), new(docker.Extractor)),
image.NewDockerImage,
RemoteSuperSet,
)
var RemoteArchiveSet = wire.NewSet(
docker.NewArchiveImageExtractor,
wire.Bind(new(extractor.Extractor), new(docker.Extractor)),
image.NewArchiveImage,
RemoteSuperSet,
)
type Scanner struct {
driver Driver
analyzer Analyzer
artifact artifact.Artifact
}
type Driver interface {
Scan(target string, imageID string, layerIDs []string, options types.ScanOptions) (results report.Results, osFound *ftypes.OS, eols bool, err error)
}
type Analyzer interface {
Analyze(ctx context.Context) (info ftypes.ImageReference, err error)
func NewScanner(driver Driver, ar artifact.Artifact) Scanner {
return Scanner{driver: driver, artifact: ar}
}
func NewScanner(driver Driver, ac Analyzer) Scanner {
return Scanner{driver: driver, analyzer: ac}
}
func (s Scanner) ScanImage(options types.ScanOptions) (report.Results, error) {
ctx := context.Background()
imageInfo, err := s.analyzer.Analyze(ctx)
func (s Scanner) ScanArtifact(ctx context.Context, options types.ScanOptions) (report.Results, error) {
artifactInfo, err := s.artifact.Inspect(ctx)
if err != nil {
return nil, xerrors.Errorf("failed analysis: %w", err)
}
log.Logger.Debugf("Image ID: %s", imageInfo.ID)
log.Logger.Debugf("Layer IDs: %v", imageInfo.LayerIDs)
log.Logger.Debugf("Artifact ID: %s", artifactInfo.ID)
log.Logger.Debugf("Blob IDs: %v", artifactInfo.BlobIDs)
results, osFound, eosl, err := s.driver.Scan(imageInfo.Name, imageInfo.ID, imageInfo.LayerIDs, options)
results, osFound, eosl, err := s.driver.Scan(artifactInfo.Name, artifactInfo.ID, artifactInfo.BlobIDs, options)
if err != nil {
return nil, xerrors.Errorf("scan failed: %w", err)
}

View File

@@ -1,6 +1,7 @@
package scanner
import (
"context"
"errors"
"os"
"testing"
@@ -8,6 +9,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/aquasecurity/fanal/artifact"
ftypes "github.com/aquasecurity/fanal/types"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/report"
@@ -20,15 +22,15 @@ func TestMain(m *testing.M) {
os.Exit(code)
}
func TestScanner_ScanImage(t *testing.T) {
func TestScanner_ScanArtifact(t *testing.T) {
type args struct {
options types.ScanOptions
}
tests := []struct {
name string
args args
analyzeExpectation AnalyzerAnalyzeExpectation
scanExpectation ScanExpectation
inspectExpectation artifact.ArtifactInspectExpectation
scanExpectation DriverScanExpectation
wantResults report.Results
wantErr string
}{
@@ -37,26 +39,26 @@ func TestScanner_ScanImage(t *testing.T) {
args: args{
options: types.ScanOptions{VulnType: []string{"os"}},
},
analyzeExpectation: AnalyzerAnalyzeExpectation{
Args: AnalyzerAnalyzeArgs{
inspectExpectation: artifact.ArtifactInspectExpectation{
Args: artifact.ArtifactInspectArgs{
CtxAnything: true,
},
Returns: AnalyzerAnalyzeReturns{
Info: ftypes.ImageReference{
Name: "alpine:3.11",
ID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
LayerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
Returns: artifact.ArtifactInspectReturns{
Reference: ftypes.ArtifactReference{
Name: "alpine:3.11",
ID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
BlobIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
},
},
},
scanExpectation: ScanExpectation{
Args: ScanArgs{
scanExpectation: DriverScanExpectation{
Args: DriverScanArgs{
Target: "alpine:3.11",
ImageID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
LayerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
Options: types.ScanOptions{VulnType: []string{"os"}},
},
Returns: ScanReturns{
Returns: DriverScanReturns{
Results: report.Results{
{
Target: "alpine:3.11",
@@ -128,11 +130,11 @@ func TestScanner_ScanImage(t *testing.T) {
args: args{
options: types.ScanOptions{VulnType: []string{"os"}},
},
analyzeExpectation: AnalyzerAnalyzeExpectation{
Args: AnalyzerAnalyzeArgs{
inspectExpectation: artifact.ArtifactInspectExpectation{
Args: artifact.ArtifactInspectArgs{
CtxAnything: true,
},
Returns: AnalyzerAnalyzeReturns{
Returns: artifact.ArtifactInspectReturns{
Err: errors.New("error"),
},
},
@@ -143,26 +145,26 @@ func TestScanner_ScanImage(t *testing.T) {
args: args{
options: types.ScanOptions{VulnType: []string{"os"}},
},
analyzeExpectation: AnalyzerAnalyzeExpectation{
Args: AnalyzerAnalyzeArgs{
inspectExpectation: artifact.ArtifactInspectExpectation{
Args: artifact.ArtifactInspectArgs{
CtxAnything: true,
},
Returns: AnalyzerAnalyzeReturns{
Info: ftypes.ImageReference{
Name: "alpine:3.11",
ID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
LayerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
Returns: artifact.ArtifactInspectReturns{
Reference: ftypes.ArtifactReference{
Name: "alpine:3.11",
ID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
BlobIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
},
},
},
scanExpectation: ScanExpectation{
Args: ScanArgs{
scanExpectation: DriverScanExpectation{
Args: DriverScanArgs{
Target: "alpine:3.11",
ImageID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
LayerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
Options: types.ScanOptions{VulnType: []string{"os"}},
},
Returns: ScanReturns{
Returns: DriverScanReturns{
Err: errors.New("error"),
},
},
@@ -174,11 +176,11 @@ func TestScanner_ScanImage(t *testing.T) {
d := new(MockDriver)
d.ApplyScanExpectation(tt.scanExpectation)
analyzer := new(MockAnalyzer)
analyzer.ApplyAnalyzeExpectation(tt.analyzeExpectation)
mockArtifact := new(artifact.MockArtifact)
mockArtifact.ApplyInspectExpectation(tt.inspectExpectation)
s := NewScanner(d, analyzer)
gotResults, err := s.ScanImage(tt.args.options)
s := NewScanner(d, mockArtifact)
gotResults, err := s.ScanArtifact(context.Background(), tt.args.options)
if tt.wantErr != "" {
require.NotNil(t, err, tt.name)
require.Contains(t, err.Error(), tt.wantErr, tt.name)

View File

@@ -23,7 +23,7 @@ var _ = math.Inf
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type ImageInfo struct {
type ArtifactInfo struct {
SchemaVersion int32 `protobuf:"varint,1,opt,name=schema_version,json=schemaVersion,proto3" json:"schema_version,omitempty"`
Architecture string `protobuf:"bytes,2,opt,name=architecture,proto3" json:"architecture,omitempty"`
Created *timestamp.Timestamp `protobuf:"bytes,3,opt,name=created,proto3" json:"created,omitempty"`
@@ -35,121 +35,121 @@ type ImageInfo struct {
XXX_sizecache int32 `json:"-"`
}
func (m *ImageInfo) Reset() { *m = ImageInfo{} }
func (m *ImageInfo) String() string { return proto.CompactTextString(m) }
func (*ImageInfo) ProtoMessage() {}
func (*ImageInfo) Descriptor() ([]byte, []int) {
func (m *ArtifactInfo) Reset() { *m = ArtifactInfo{} }
func (m *ArtifactInfo) String() string { return proto.CompactTextString(m) }
func (*ArtifactInfo) ProtoMessage() {}
func (*ArtifactInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_1f1f7d564abadf42, []int{0}
}
func (m *ImageInfo) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ImageInfo.Unmarshal(m, b)
func (m *ArtifactInfo) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ArtifactInfo.Unmarshal(m, b)
}
func (m *ImageInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ImageInfo.Marshal(b, m, deterministic)
func (m *ArtifactInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ArtifactInfo.Marshal(b, m, deterministic)
}
func (m *ImageInfo) XXX_Merge(src proto.Message) {
xxx_messageInfo_ImageInfo.Merge(m, src)
func (m *ArtifactInfo) XXX_Merge(src proto.Message) {
xxx_messageInfo_ArtifactInfo.Merge(m, src)
}
func (m *ImageInfo) XXX_Size() int {
return xxx_messageInfo_ImageInfo.Size(m)
func (m *ArtifactInfo) XXX_Size() int {
return xxx_messageInfo_ArtifactInfo.Size(m)
}
func (m *ImageInfo) XXX_DiscardUnknown() {
xxx_messageInfo_ImageInfo.DiscardUnknown(m)
func (m *ArtifactInfo) XXX_DiscardUnknown() {
xxx_messageInfo_ArtifactInfo.DiscardUnknown(m)
}
var xxx_messageInfo_ImageInfo proto.InternalMessageInfo
var xxx_messageInfo_ArtifactInfo proto.InternalMessageInfo
func (m *ImageInfo) GetSchemaVersion() int32 {
func (m *ArtifactInfo) GetSchemaVersion() int32 {
if m != nil {
return m.SchemaVersion
}
return 0
}
func (m *ImageInfo) GetArchitecture() string {
func (m *ArtifactInfo) GetArchitecture() string {
if m != nil {
return m.Architecture
}
return ""
}
func (m *ImageInfo) GetCreated() *timestamp.Timestamp {
func (m *ArtifactInfo) GetCreated() *timestamp.Timestamp {
if m != nil {
return m.Created
}
return nil
}
func (m *ImageInfo) GetDockerVersion() string {
func (m *ArtifactInfo) GetDockerVersion() string {
if m != nil {
return m.DockerVersion
}
return ""
}
func (m *ImageInfo) GetOs() string {
func (m *ArtifactInfo) GetOs() string {
if m != nil {
return m.Os
}
return ""
}
func (m *ImageInfo) GetHistoryPackages() []*common.Package {
func (m *ArtifactInfo) GetHistoryPackages() []*common.Package {
if m != nil {
return m.HistoryPackages
}
return nil
}
type PutImageRequest struct {
ImageId string `protobuf:"bytes,1,opt,name=image_id,json=imageId,proto3" json:"image_id,omitempty"`
ImageInfo *ImageInfo `protobuf:"bytes,2,opt,name=image_info,json=imageInfo,proto3" json:"image_info,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
type PutArtifactRequest struct {
ArtifactId string `protobuf:"bytes,1,opt,name=artifact_id,json=artifactId,proto3" json:"artifact_id,omitempty"`
ArtifactInfo *ArtifactInfo `protobuf:"bytes,2,opt,name=artifact_info,json=artifactInfo,proto3" json:"artifact_info,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *PutImageRequest) Reset() { *m = PutImageRequest{} }
func (m *PutImageRequest) String() string { return proto.CompactTextString(m) }
func (*PutImageRequest) ProtoMessage() {}
func (*PutImageRequest) Descriptor() ([]byte, []int) {
func (m *PutArtifactRequest) Reset() { *m = PutArtifactRequest{} }
func (m *PutArtifactRequest) String() string { return proto.CompactTextString(m) }
func (*PutArtifactRequest) ProtoMessage() {}
func (*PutArtifactRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_1f1f7d564abadf42, []int{1}
}
func (m *PutImageRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PutImageRequest.Unmarshal(m, b)
func (m *PutArtifactRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PutArtifactRequest.Unmarshal(m, b)
}
func (m *PutImageRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_PutImageRequest.Marshal(b, m, deterministic)
func (m *PutArtifactRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_PutArtifactRequest.Marshal(b, m, deterministic)
}
func (m *PutImageRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_PutImageRequest.Merge(m, src)
func (m *PutArtifactRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_PutArtifactRequest.Merge(m, src)
}
func (m *PutImageRequest) XXX_Size() int {
return xxx_messageInfo_PutImageRequest.Size(m)
func (m *PutArtifactRequest) XXX_Size() int {
return xxx_messageInfo_PutArtifactRequest.Size(m)
}
func (m *PutImageRequest) XXX_DiscardUnknown() {
xxx_messageInfo_PutImageRequest.DiscardUnknown(m)
func (m *PutArtifactRequest) XXX_DiscardUnknown() {
xxx_messageInfo_PutArtifactRequest.DiscardUnknown(m)
}
var xxx_messageInfo_PutImageRequest proto.InternalMessageInfo
var xxx_messageInfo_PutArtifactRequest proto.InternalMessageInfo
func (m *PutImageRequest) GetImageId() string {
func (m *PutArtifactRequest) GetArtifactId() string {
if m != nil {
return m.ImageId
return m.ArtifactId
}
return ""
}
func (m *PutImageRequest) GetImageInfo() *ImageInfo {
func (m *PutArtifactRequest) GetArtifactInfo() *ArtifactInfo {
if m != nil {
return m.ImageInfo
return m.ArtifactInfo
}
return nil
}
type LayerInfo struct {
type BlobInfo struct {
SchemaVersion int32 `protobuf:"varint,1,opt,name=schema_version,json=schemaVersion,proto3" json:"schema_version,omitempty"`
Os *common.OS `protobuf:"bytes,2,opt,name=os,proto3" json:"os,omitempty"`
PackageInfos []*common.PackageInfo `protobuf:"bytes,3,rep,name=package_infos,json=packageInfos,proto3" json:"package_infos,omitempty"`
@@ -163,130 +163,130 @@ type LayerInfo struct {
XXX_sizecache int32 `json:"-"`
}
func (m *LayerInfo) Reset() { *m = LayerInfo{} }
func (m *LayerInfo) String() string { return proto.CompactTextString(m) }
func (*LayerInfo) ProtoMessage() {}
func (*LayerInfo) Descriptor() ([]byte, []int) {
func (m *BlobInfo) Reset() { *m = BlobInfo{} }
func (m *BlobInfo) String() string { return proto.CompactTextString(m) }
func (*BlobInfo) ProtoMessage() {}
func (*BlobInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_1f1f7d564abadf42, []int{2}
}
func (m *LayerInfo) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_LayerInfo.Unmarshal(m, b)
func (m *BlobInfo) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_BlobInfo.Unmarshal(m, b)
}
func (m *LayerInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_LayerInfo.Marshal(b, m, deterministic)
func (m *BlobInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_BlobInfo.Marshal(b, m, deterministic)
}
func (m *LayerInfo) XXX_Merge(src proto.Message) {
xxx_messageInfo_LayerInfo.Merge(m, src)
func (m *BlobInfo) XXX_Merge(src proto.Message) {
xxx_messageInfo_BlobInfo.Merge(m, src)
}
func (m *LayerInfo) XXX_Size() int {
return xxx_messageInfo_LayerInfo.Size(m)
func (m *BlobInfo) XXX_Size() int {
return xxx_messageInfo_BlobInfo.Size(m)
}
func (m *LayerInfo) XXX_DiscardUnknown() {
xxx_messageInfo_LayerInfo.DiscardUnknown(m)
func (m *BlobInfo) XXX_DiscardUnknown() {
xxx_messageInfo_BlobInfo.DiscardUnknown(m)
}
var xxx_messageInfo_LayerInfo proto.InternalMessageInfo
var xxx_messageInfo_BlobInfo proto.InternalMessageInfo
func (m *LayerInfo) GetSchemaVersion() int32 {
func (m *BlobInfo) GetSchemaVersion() int32 {
if m != nil {
return m.SchemaVersion
}
return 0
}
func (m *LayerInfo) GetOs() *common.OS {
func (m *BlobInfo) GetOs() *common.OS {
if m != nil {
return m.Os
}
return nil
}
func (m *LayerInfo) GetPackageInfos() []*common.PackageInfo {
func (m *BlobInfo) GetPackageInfos() []*common.PackageInfo {
if m != nil {
return m.PackageInfos
}
return nil
}
func (m *LayerInfo) GetApplications() []*common.Application {
func (m *BlobInfo) GetApplications() []*common.Application {
if m != nil {
return m.Applications
}
return nil
}
func (m *LayerInfo) GetOpaqueDirs() []string {
func (m *BlobInfo) GetOpaqueDirs() []string {
if m != nil {
return m.OpaqueDirs
}
return nil
}
func (m *LayerInfo) GetWhiteoutFiles() []string {
func (m *BlobInfo) GetWhiteoutFiles() []string {
if m != nil {
return m.WhiteoutFiles
}
return nil
}
func (m *LayerInfo) GetDigest() string {
func (m *BlobInfo) GetDigest() string {
if m != nil {
return m.Digest
}
return ""
}
func (m *LayerInfo) GetDiffId() string {
func (m *BlobInfo) GetDiffId() string {
if m != nil {
return m.DiffId
}
return ""
}
type PutLayerRequest struct {
DiffId string `protobuf:"bytes,1,opt,name=diff_id,json=diffId,proto3" json:"diff_id,omitempty"`
LayerInfo *LayerInfo `protobuf:"bytes,3,opt,name=layer_info,json=layerInfo,proto3" json:"layer_info,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
type PutBlobRequest struct {
DiffId string `protobuf:"bytes,1,opt,name=diff_id,json=diffId,proto3" json:"diff_id,omitempty"`
BlobInfo *BlobInfo `protobuf:"bytes,3,opt,name=blob_info,json=blobInfo,proto3" json:"blob_info,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *PutLayerRequest) Reset() { *m = PutLayerRequest{} }
func (m *PutLayerRequest) String() string { return proto.CompactTextString(m) }
func (*PutLayerRequest) ProtoMessage() {}
func (*PutLayerRequest) Descriptor() ([]byte, []int) {
func (m *PutBlobRequest) Reset() { *m = PutBlobRequest{} }
func (m *PutBlobRequest) String() string { return proto.CompactTextString(m) }
func (*PutBlobRequest) ProtoMessage() {}
func (*PutBlobRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_1f1f7d564abadf42, []int{3}
}
func (m *PutLayerRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PutLayerRequest.Unmarshal(m, b)
func (m *PutBlobRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PutBlobRequest.Unmarshal(m, b)
}
func (m *PutLayerRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_PutLayerRequest.Marshal(b, m, deterministic)
func (m *PutBlobRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_PutBlobRequest.Marshal(b, m, deterministic)
}
func (m *PutLayerRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_PutLayerRequest.Merge(m, src)
func (m *PutBlobRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_PutBlobRequest.Merge(m, src)
}
func (m *PutLayerRequest) XXX_Size() int {
return xxx_messageInfo_PutLayerRequest.Size(m)
func (m *PutBlobRequest) XXX_Size() int {
return xxx_messageInfo_PutBlobRequest.Size(m)
}
func (m *PutLayerRequest) XXX_DiscardUnknown() {
xxx_messageInfo_PutLayerRequest.DiscardUnknown(m)
func (m *PutBlobRequest) XXX_DiscardUnknown() {
xxx_messageInfo_PutBlobRequest.DiscardUnknown(m)
}
var xxx_messageInfo_PutLayerRequest proto.InternalMessageInfo
var xxx_messageInfo_PutBlobRequest proto.InternalMessageInfo
func (m *PutLayerRequest) GetDiffId() string {
func (m *PutBlobRequest) GetDiffId() string {
if m != nil {
return m.DiffId
}
return ""
}
func (m *PutLayerRequest) GetLayerInfo() *LayerInfo {
func (m *PutBlobRequest) GetBlobInfo() *BlobInfo {
if m != nil {
return m.LayerInfo
return m.BlobInfo
}
return nil
}
@@ -338,155 +338,155 @@ func (m *PutResponse) GetEosl() bool {
return false
}
type MissingLayersRequest struct {
ImageId string `protobuf:"bytes,1,opt,name=image_id,json=imageId,proto3" json:"image_id,omitempty"`
LayerIds []string `protobuf:"bytes,2,rep,name=layer_ids,json=layerIds,proto3" json:"layer_ids,omitempty"`
type MissingBlobsRequest struct {
ArtifactId string `protobuf:"bytes,1,opt,name=artifact_id,json=artifactId,proto3" json:"artifact_id,omitempty"`
BlobIds []string `protobuf:"bytes,2,rep,name=blob_ids,json=blobIds,proto3" json:"blob_ids,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *MissingLayersRequest) Reset() { *m = MissingLayersRequest{} }
func (m *MissingLayersRequest) String() string { return proto.CompactTextString(m) }
func (*MissingLayersRequest) ProtoMessage() {}
func (*MissingLayersRequest) Descriptor() ([]byte, []int) {
func (m *MissingBlobsRequest) Reset() { *m = MissingBlobsRequest{} }
func (m *MissingBlobsRequest) String() string { return proto.CompactTextString(m) }
func (*MissingBlobsRequest) ProtoMessage() {}
func (*MissingBlobsRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_1f1f7d564abadf42, []int{5}
}
func (m *MissingLayersRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_MissingLayersRequest.Unmarshal(m, b)
func (m *MissingBlobsRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_MissingBlobsRequest.Unmarshal(m, b)
}
func (m *MissingLayersRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_MissingLayersRequest.Marshal(b, m, deterministic)
func (m *MissingBlobsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_MissingBlobsRequest.Marshal(b, m, deterministic)
}
func (m *MissingLayersRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_MissingLayersRequest.Merge(m, src)
func (m *MissingBlobsRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_MissingBlobsRequest.Merge(m, src)
}
func (m *MissingLayersRequest) XXX_Size() int {
return xxx_messageInfo_MissingLayersRequest.Size(m)
func (m *MissingBlobsRequest) XXX_Size() int {
return xxx_messageInfo_MissingBlobsRequest.Size(m)
}
func (m *MissingLayersRequest) XXX_DiscardUnknown() {
xxx_messageInfo_MissingLayersRequest.DiscardUnknown(m)
func (m *MissingBlobsRequest) XXX_DiscardUnknown() {
xxx_messageInfo_MissingBlobsRequest.DiscardUnknown(m)
}
var xxx_messageInfo_MissingLayersRequest proto.InternalMessageInfo
var xxx_messageInfo_MissingBlobsRequest proto.InternalMessageInfo
func (m *MissingLayersRequest) GetImageId() string {
func (m *MissingBlobsRequest) GetArtifactId() string {
if m != nil {
return m.ImageId
return m.ArtifactId
}
return ""
}
func (m *MissingLayersRequest) GetLayerIds() []string {
func (m *MissingBlobsRequest) GetBlobIds() []string {
if m != nil {
return m.LayerIds
return m.BlobIds
}
return nil
}
type MissingLayersResponse struct {
MissingImage bool `protobuf:"varint,1,opt,name=missing_image,json=missingImage,proto3" json:"missing_image,omitempty"`
MissingLayerIds []string `protobuf:"bytes,2,rep,name=missing_layer_ids,json=missingLayerIds,proto3" json:"missing_layer_ids,omitempty"`
type MissingBlobsResponse struct {
MissingArtifact bool `protobuf:"varint,1,opt,name=missing_artifact,json=missingArtifact,proto3" json:"missing_artifact,omitempty"`
MissingBlobIds []string `protobuf:"bytes,2,rep,name=missing_blob_ids,json=missingBlobIds,proto3" json:"missing_blob_ids,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *MissingLayersResponse) Reset() { *m = MissingLayersResponse{} }
func (m *MissingLayersResponse) String() string { return proto.CompactTextString(m) }
func (*MissingLayersResponse) ProtoMessage() {}
func (*MissingLayersResponse) Descriptor() ([]byte, []int) {
func (m *MissingBlobsResponse) Reset() { *m = MissingBlobsResponse{} }
func (m *MissingBlobsResponse) String() string { return proto.CompactTextString(m) }
func (*MissingBlobsResponse) ProtoMessage() {}
func (*MissingBlobsResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_1f1f7d564abadf42, []int{6}
}
func (m *MissingLayersResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_MissingLayersResponse.Unmarshal(m, b)
func (m *MissingBlobsResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_MissingBlobsResponse.Unmarshal(m, b)
}
func (m *MissingLayersResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_MissingLayersResponse.Marshal(b, m, deterministic)
func (m *MissingBlobsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_MissingBlobsResponse.Marshal(b, m, deterministic)
}
func (m *MissingLayersResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_MissingLayersResponse.Merge(m, src)
func (m *MissingBlobsResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_MissingBlobsResponse.Merge(m, src)
}
func (m *MissingLayersResponse) XXX_Size() int {
return xxx_messageInfo_MissingLayersResponse.Size(m)
func (m *MissingBlobsResponse) XXX_Size() int {
return xxx_messageInfo_MissingBlobsResponse.Size(m)
}
func (m *MissingLayersResponse) XXX_DiscardUnknown() {
xxx_messageInfo_MissingLayersResponse.DiscardUnknown(m)
func (m *MissingBlobsResponse) XXX_DiscardUnknown() {
xxx_messageInfo_MissingBlobsResponse.DiscardUnknown(m)
}
var xxx_messageInfo_MissingLayersResponse proto.InternalMessageInfo
var xxx_messageInfo_MissingBlobsResponse proto.InternalMessageInfo
func (m *MissingLayersResponse) GetMissingImage() bool {
func (m *MissingBlobsResponse) GetMissingArtifact() bool {
if m != nil {
return m.MissingImage
return m.MissingArtifact
}
return false
}
func (m *MissingLayersResponse) GetMissingLayerIds() []string {
func (m *MissingBlobsResponse) GetMissingBlobIds() []string {
if m != nil {
return m.MissingLayerIds
return m.MissingBlobIds
}
return nil
}
func init() {
proto.RegisterType((*ImageInfo)(nil), "trivy.cache.v1.ImageInfo")
proto.RegisterType((*PutImageRequest)(nil), "trivy.cache.v1.PutImageRequest")
proto.RegisterType((*LayerInfo)(nil), "trivy.cache.v1.LayerInfo")
proto.RegisterType((*PutLayerRequest)(nil), "trivy.cache.v1.PutLayerRequest")
proto.RegisterType((*ArtifactInfo)(nil), "trivy.cache.v1.ArtifactInfo")
proto.RegisterType((*PutArtifactRequest)(nil), "trivy.cache.v1.PutArtifactRequest")
proto.RegisterType((*BlobInfo)(nil), "trivy.cache.v1.BlobInfo")
proto.RegisterType((*PutBlobRequest)(nil), "trivy.cache.v1.PutBlobRequest")
proto.RegisterType((*PutResponse)(nil), "trivy.cache.v1.PutResponse")
proto.RegisterType((*MissingLayersRequest)(nil), "trivy.cache.v1.MissingLayersRequest")
proto.RegisterType((*MissingLayersResponse)(nil), "trivy.cache.v1.MissingLayersResponse")
proto.RegisterType((*MissingBlobsRequest)(nil), "trivy.cache.v1.MissingBlobsRequest")
proto.RegisterType((*MissingBlobsResponse)(nil), "trivy.cache.v1.MissingBlobsResponse")
}
func init() { proto.RegisterFile("rpc/cache/service.proto", fileDescriptor_1f1f7d564abadf42) }
var fileDescriptor_1f1f7d564abadf42 = []byte{
// 674 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0xdd, 0x6e, 0xd3, 0x30,
0x14, 0x56, 0xdb, 0x75, 0x6d, 0x4e, 0xdb, 0x6d, 0x58, 0x6c, 0xcb, 0xba, 0x8b, 0x55, 0x81, 0x49,
0x15, 0x17, 0x89, 0x28, 0x08, 0x71, 0x03, 0x02, 0x06, 0x48, 0x95, 0xf8, 0x99, 0x0c, 0xe2, 0x02,
0x21, 0x55, 0x5e, 0xe2, 0xa4, 0xd6, 0x9a, 0x38, 0xb3, 0x9d, 0xa2, 0x3e, 0x00, 0x6f, 0xc7, 0xbb,
0xf0, 0x0a, 0x28, 0x27, 0xc9, 0xd6, 0x96, 0xf2, 0x77, 0xe7, 0xf3, 0x93, 0xef, 0x7c, 0xe7, 0xfb,
0xec, 0xc0, 0xa1, 0x4a, 0x7d, 0xcf, 0x67, 0xfe, 0x94, 0x7b, 0x9a, 0xab, 0xb9, 0xf0, 0xb9, 0x9b,
0x2a, 0x69, 0x24, 0xd9, 0x31, 0x4a, 0xcc, 0x17, 0x2e, 0x96, 0xdc, 0xf9, 0xfd, 0xfe, 0x49, 0x24,
0x65, 0x34, 0xe3, 0x1e, 0x56, 0x2f, 0xb2, 0xd0, 0x33, 0x22, 0xe6, 0xda, 0xb0, 0x38, 0x2d, 0x3e,
0xe8, 0x3f, 0x8a, 0x84, 0x99, 0x66, 0x17, 0xae, 0x2f, 0x63, 0x8f, 0x5d, 0x65, 0x4c, 0x73, 0x3f,
0x53, 0xc2, 0x2c, 0x3c, 0x04, 0xf2, 0x70, 0x8e, 0x8c, 0x63, 0x99, 0xac, 0x0e, 0xea, 0x1f, 0xaf,
0x03, 0xf3, 0x38, 0x35, 0x8b, 0xa2, 0xe8, 0x7c, 0xab, 0x83, 0x35, 0x8e, 0x59, 0xc4, 0xc7, 0x49,
0x28, 0xc9, 0x29, 0xec, 0x68, 0x7f, 0xca, 0x63, 0x36, 0x99, 0x73, 0xa5, 0x85, 0x4c, 0xec, 0xda,
0xa0, 0x36, 0x6c, 0xd2, 0x5e, 0x91, 0xfd, 0x54, 0x24, 0x89, 0x03, 0x5d, 0xa6, 0xfc, 0xa9, 0x30,
0xdc, 0x37, 0x99, 0xe2, 0x76, 0x7d, 0x50, 0x1b, 0x5a, 0x74, 0x25, 0x47, 0x1e, 0x42, 0xcb, 0x57,
0x9c, 0x19, 0x1e, 0xd8, 0x8d, 0x41, 0x6d, 0xd8, 0x19, 0xf5, 0xdd, 0x82, 0x87, 0x5b, 0xf1, 0x70,
0x3f, 0x56, 0x0b, 0xd2, 0xaa, 0x35, 0x27, 0x10, 0x48, 0xff, 0x92, 0xab, 0x6b, 0x02, 0x5b, 0x88,
0xdd, 0x2b, 0xb2, 0x15, 0x81, 0x1d, 0xa8, 0x4b, 0x6d, 0x37, 0xb1, 0x54, 0x97, 0x9a, 0x3c, 0x83,
0xbd, 0xa9, 0xd0, 0x46, 0xaa, 0xc5, 0x24, 0x65, 0xfe, 0x25, 0x8b, 0xb8, 0xb6, 0xb7, 0x07, 0x8d,
0x61, 0x67, 0xb4, 0xef, 0x96, 0x32, 0xa3, 0x32, 0xee, 0x79, 0x51, 0xa5, 0xbb, 0x65, 0x7b, 0x19,
0x6b, 0x27, 0x84, 0xdd, 0xf3, 0xcc, 0xa0, 0x12, 0x94, 0x5f, 0x65, 0x5c, 0x1b, 0x72, 0x04, 0x6d,
0x91, 0xc7, 0x13, 0x11, 0xa0, 0x0c, 0x16, 0x6d, 0x61, 0x3c, 0x0e, 0xc8, 0x63, 0x80, 0xb2, 0x94,
0x84, 0x12, 0xd7, 0xef, 0x8c, 0x8e, 0xdc, 0x55, 0x43, 0xdd, 0x6b, 0x59, 0xa9, 0x25, 0xaa, 0xa3,
0xf3, 0xbd, 0x0e, 0xd6, 0x1b, 0xb6, 0xe0, 0xea, 0x7f, 0xf4, 0x1e, 0xe0, 0xba, 0xc5, 0x98, 0xbd,
0xd5, 0x85, 0xde, 0x7f, 0x40, 0x01, 0x9e, 0x42, 0xaf, 0x5c, 0x1c, 0x29, 0x69, 0xbb, 0x81, 0xdb,
0x1f, 0x6d, 0xdc, 0x1e, 0x39, 0x75, 0xd3, 0x9b, 0x40, 0x93, 0x27, 0xd0, 0x65, 0x69, 0x3a, 0x13,
0x3e, 0x33, 0x42, 0x26, 0xda, 0xde, 0xda, 0xf4, 0xf9, 0xf3, 0x9b, 0x0e, 0xba, 0xd2, 0x4e, 0x4e,
0xa0, 0x23, 0x53, 0x76, 0x95, 0xf1, 0x49, 0x20, 0x54, 0x6e, 0x4c, 0x63, 0x68, 0x51, 0x28, 0x52,
0x2f, 0x85, 0xd2, 0xf9, 0xa2, 0x5f, 0xf3, 0xbb, 0x21, 0x33, 0x33, 0x09, 0xc5, 0xac, 0xb4, 0xc7,
0xa2, 0xbd, 0x2a, 0xfb, 0x3a, 0x4f, 0x92, 0x03, 0xd8, 0x0e, 0x44, 0xc4, 0xb5, 0xb1, 0x5b, 0x28,
0x78, 0x19, 0x91, 0x43, 0x68, 0x05, 0x22, 0x0c, 0x73, 0x27, 0xda, 0x55, 0x21, 0x0c, 0xc7, 0x81,
0x13, 0xa0, 0x6d, 0x28, 0x68, 0x65, 0xdb, 0x52, 0x6f, 0x6d, 0xb9, 0x37, 0x37, 0x6d, 0x96, 0x37,
0x16, 0xa6, 0x35, 0x36, 0x9b, 0x76, 0xed, 0x0d, 0xb5, 0x66, 0xd5, 0xd1, 0x39, 0x83, 0xce, 0x79,
0x66, 0x28, 0xd7, 0xa9, 0x4c, 0x34, 0x2f, 0xed, 0xa8, 0xfd, 0xc1, 0x0e, 0x02, 0x5b, 0x5c, 0xea,
0x19, 0x5a, 0xd6, 0xa6, 0x78, 0x76, 0xde, 0xc1, 0xed, 0xb7, 0x42, 0x6b, 0x91, 0x44, 0x38, 0x43,
0xff, 0xc3, 0x35, 0x3b, 0x06, 0xab, 0x64, 0x1c, 0xe4, 0xf6, 0xe7, 0x82, 0xb5, 0x0b, 0x56, 0x81,
0x76, 0xa6, 0xb0, 0xbf, 0x86, 0x57, 0xd2, 0xbb, 0x03, 0xbd, 0xb8, 0x28, 0x4c, 0x10, 0x08, 0x51,
0xdb, 0xb4, 0x5b, 0x26, 0xf1, 0x5a, 0x92, 0x7b, 0x70, 0xab, 0x6a, 0x5a, 0x1f, 0xb1, 0x1b, 0x2f,
0xc1, 0x8e, 0x03, 0x3d, 0xfa, 0x51, 0x83, 0xe6, 0x59, 0x2e, 0x10, 0x39, 0x83, 0x76, 0xf5, 0x4a,
0xc8, 0xc9, 0xba, 0x74, 0x6b, 0xef, 0xa7, 0x7f, 0xf0, 0xcb, 0x83, 0x7f, 0x95, 0xff, 0x78, 0x4a,
0x10, 0x44, 0xdf, 0x08, 0xb2, 0xec, 0xe6, 0x6f, 0x41, 0xbe, 0x40, 0x6f, 0x65, 0x7b, 0x72, 0x77,
0x1d, 0x69, 0x93, 0xd8, 0xfd, 0xd3, 0xbf, 0x74, 0x15, 0x12, 0xbe, 0x68, 0x7d, 0x6e, 0x62, 0xc7,
0xc5, 0x36, 0x8e, 0x7d, 0xf0, 0x33, 0x00, 0x00, 0xff, 0xff, 0x08, 0x8d, 0x6f, 0x9e, 0xc6, 0x05,
0x00, 0x00,
// 682 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x94, 0xdd, 0x6e, 0xd3, 0x3e,
0x18, 0xc6, 0xd5, 0x76, 0x5d, 0xdb, 0xb7, 0x1f, 0x9b, 0xfc, 0xff, 0xb3, 0x65, 0x05, 0xb1, 0x2a,
0x80, 0x54, 0x4e, 0x52, 0x51, 0x3e, 0xce, 0x40, 0x74, 0x03, 0xa4, 0x1e, 0x20, 0x4a, 0x40, 0x48,
0x70, 0x52, 0x5c, 0xc7, 0x69, 0xad, 0x35, 0x71, 0x66, 0x3b, 0x85, 0xde, 0x01, 0xf7, 0xc6, 0xcd,
0x70, 0x09, 0xc8, 0x76, 0xb2, 0x7e, 0xac, 0x4c, 0x70, 0x16, 0x3f, 0x7e, 0xf3, 0xbc, 0xaf, 0x7f,
0x8f, 0x13, 0x38, 0x16, 0x09, 0xe9, 0x11, 0x4c, 0x66, 0xb4, 0x27, 0xa9, 0x58, 0x30, 0x42, 0xbd,
0x44, 0x70, 0xc5, 0x51, 0x4b, 0x09, 0xb6, 0x58, 0x7a, 0x66, 0xcb, 0x5b, 0x3c, 0x6a, 0x9f, 0x4e,
0x39, 0x9f, 0xce, 0x69, 0xcf, 0xec, 0x4e, 0xd2, 0xb0, 0xa7, 0x58, 0x44, 0xa5, 0xc2, 0x51, 0x62,
0x5f, 0x68, 0x3f, 0x9b, 0x32, 0x35, 0x4b, 0x27, 0x1e, 0xe1, 0x51, 0x0f, 0x5f, 0xa6, 0x58, 0x52,
0x92, 0x0a, 0xa6, 0x96, 0x3d, 0x63, 0xd4, 0x33, 0x7d, 0x78, 0x14, 0xf1, 0x78, 0xb3, 0x51, 0xfb,
0xf6, 0xb6, 0x31, 0x8d, 0x12, 0xb5, 0xb4, 0x9b, 0xee, 0x8f, 0x22, 0x34, 0x06, 0x42, 0xb1, 0x10,
0x13, 0x35, 0x8c, 0x43, 0x8e, 0x1e, 0x40, 0x4b, 0x92, 0x19, 0x8d, 0xf0, 0x78, 0x41, 0x85, 0x64,
0x3c, 0x76, 0x0a, 0x9d, 0x42, 0xb7, 0xec, 0x37, 0xad, 0xfa, 0xc9, 0x8a, 0xc8, 0x85, 0x06, 0x16,
0x64, 0xc6, 0x14, 0x25, 0x2a, 0x15, 0xd4, 0x29, 0x76, 0x0a, 0xdd, 0x9a, 0xbf, 0xa1, 0xa1, 0x27,
0x50, 0x21, 0x82, 0x62, 0x45, 0x03, 0xa7, 0xd4, 0x29, 0x74, 0xeb, 0xfd, 0xb6, 0x67, 0x47, 0xf1,
0xf2, 0x51, 0xbc, 0x8f, 0xf9, 0x19, 0xfd, 0xbc, 0x54, 0x0f, 0x10, 0x70, 0x72, 0x41, 0xc5, 0xd5,
0x00, 0x7b, 0xc6, 0xbb, 0x69, 0xd5, 0x7c, 0x80, 0x16, 0x14, 0xb9, 0x74, 0xca, 0x66, 0xab, 0xc8,
0x25, 0x7a, 0x09, 0x87, 0x33, 0x26, 0x15, 0x17, 0xcb, 0x71, 0x82, 0xc9, 0x05, 0x9e, 0x52, 0xe9,
0xec, 0x77, 0x4a, 0xdd, 0x7a, 0xff, 0x96, 0x97, 0x91, 0x36, 0x70, 0xbc, 0x91, 0xdd, 0xf5, 0x0f,
0xb2, 0xf2, 0x6c, 0x2d, 0xdd, 0xef, 0x80, 0x46, 0xa9, 0xca, 0x61, 0xf8, 0xf4, 0x32, 0xa5, 0x52,
0xa1, 0x53, 0xa8, 0xe3, 0x4c, 0x1a, 0xb3, 0xc0, 0xc0, 0xa8, 0xf9, 0x90, 0x4b, 0xc3, 0x00, 0x0d,
0xa0, 0xb9, 0x2a, 0x88, 0x43, 0x6e, 0x50, 0xd4, 0xfb, 0x77, 0xbc, 0xcd, 0x7c, 0xbd, 0x75, 0xca,
0x1a, 0xd4, 0x6a, 0xe5, 0xfe, 0x2c, 0x42, 0xf5, 0x6c, 0xce, 0x27, 0xff, 0x12, 0x40, 0xc7, 0x9c,
0xdf, 0xf6, 0x3a, 0xdc, 0x3c, 0xe1, 0xbb, 0x0f, 0x86, 0xc8, 0x0b, 0x68, 0x66, 0x24, 0xcc, 0x5c,
0xd2, 0x29, 0x19, 0x1c, 0x27, 0x3b, 0x71, 0xd8, 0xa9, 0x92, 0xd5, 0x42, 0xa2, 0xe7, 0xd0, 0xc0,
0x49, 0x32, 0x67, 0x04, 0x2b, 0xc6, 0x63, 0xe9, 0xec, 0xed, 0x7a, 0x7d, 0xb0, 0xaa, 0xf0, 0x37,
0xca, 0x35, 0x38, 0x9e, 0xe0, 0xcb, 0x94, 0x8e, 0x03, 0x26, 0x74, 0x52, 0x25, 0x0d, 0xce, 0x4a,
0xaf, 0x98, 0x90, 0xfa, 0xa0, 0xdf, 0xf4, 0x65, 0xe1, 0xa9, 0x1a, 0x87, 0x6c, 0x9e, 0xe5, 0x55,
0xf3, 0x9b, 0xb9, 0xfa, 0x46, 0x8b, 0xe8, 0x08, 0xf6, 0x03, 0x36, 0xa5, 0x52, 0x39, 0x15, 0xc3,
0x3e, 0x5b, 0xa1, 0x63, 0xa8, 0x04, 0x2c, 0x0c, 0x75, 0x28, 0xd5, 0x7c, 0x23, 0x0c, 0x87, 0x81,
0xfb, 0x15, 0x5a, 0xa3, 0x54, 0x69, 0x9e, 0x79, 0x86, 0x6b, 0xa5, 0x85, 0xf5, 0x52, 0xf4, 0x14,
0x6a, 0x93, 0x39, 0x9f, 0xd8, 0xdc, 0xec, 0x1d, 0x75, 0xb6, 0x73, 0xcb, 0x83, 0xf1, 0xab, 0x93,
0xec, 0xc9, 0x3d, 0x87, 0xfa, 0x28, 0x55, 0x3e, 0x95, 0x09, 0x8f, 0x25, 0xcd, 0xa2, 0x28, 0xdc,
0x10, 0x05, 0x82, 0x3d, 0xca, 0xe5, 0xdc, 0xc4, 0x55, 0xf5, 0xcd, 0xb3, 0xfb, 0x1e, 0xfe, 0x7b,
0xcb, 0xa4, 0x64, 0xf1, 0x54, 0x77, 0x90, 0x7f, 0x7d, 0xdf, 0x4e, 0xa0, 0x6a, 0x67, 0x0e, 0x74,
0xfc, 0x1a, 0x58, 0xc5, 0x0c, 0x16, 0x48, 0xf7, 0x02, 0xfe, 0xdf, 0xb4, 0xcc, 0x06, 0x7c, 0x08,
0x87, 0x91, 0xd5, 0xc7, 0xb9, 0x91, 0x31, 0xae, 0xfa, 0x07, 0x99, 0x9e, 0x5f, 0x4e, 0xd4, 0x5d,
0x95, 0x6e, 0x75, 0x69, 0x45, 0x2b, 0xeb, 0x61, 0x20, 0xfb, 0xbf, 0x0a, 0x50, 0x3e, 0xd7, 0x90,
0xd0, 0xd0, 0xe0, 0xb8, 0xb2, 0x70, 0xb7, 0x09, 0x5e, 0xff, 0xaa, 0xda, 0x47, 0xd7, 0xfe, 0x04,
0xaf, 0xf5, 0x4f, 0x09, 0x0d, 0xa0, 0x92, 0x65, 0x87, 0xee, 0xee, 0xb0, 0x59, 0x0b, 0xf5, 0x8f,
0x16, 0x9f, 0xa1, 0xb1, 0x0e, 0x01, 0xdd, 0xdb, 0xf6, 0xd9, 0x41, 0xbd, 0x7d, 0xff, 0xe6, 0x22,
0xcb, 0xf1, 0xac, 0xf2, 0xa5, 0x6c, 0x0a, 0x26, 0xfb, 0xa6, 0xe7, 0xe3, 0xdf, 0x01, 0x00, 0x00,
0xff, 0xff, 0xf9, 0x1a, 0xc0, 0xa0, 0xdd, 0x05, 0x00, 0x00,
}

View File

@@ -8,12 +8,12 @@ import "github.com/aquasecurity/trivy/rpc/common/service.proto";
import "google/protobuf/empty.proto";
service Cache {
rpc PutImage(PutImageRequest) returns (google.protobuf.Empty);
rpc PutLayer(PutLayerRequest) returns (google.protobuf.Empty);
rpc MissingLayers(MissingLayersRequest) returns (MissingLayersResponse);
rpc PutArtifact(PutArtifactRequest) returns (google.protobuf.Empty);
rpc PutBlob(PutBlobRequest) returns (google.protobuf.Empty);
rpc MissingBlobs(MissingBlobsRequest) returns (MissingBlobsResponse);
}
message ImageInfo {
message ArtifactInfo {
int32 schema_version = 1;
string architecture = 2;
google.protobuf.Timestamp created = 3;
@@ -22,12 +22,12 @@ message ImageInfo {
repeated common.Package history_packages = 6;
}
message PutImageRequest {
string image_id = 1;
ImageInfo image_info = 2;
message PutArtifactRequest {
string artifact_id = 1;
ArtifactInfo artifact_info = 2;
}
message LayerInfo {
message BlobInfo {
int32 schema_version = 1;
common.OS os = 2;
repeated common.PackageInfo package_infos = 3;
@@ -38,9 +38,9 @@ message LayerInfo {
string diff_id = 8;
}
message PutLayerRequest {
string diff_id = 1;
LayerInfo layer_info = 3;
message PutBlobRequest {
string diff_id = 1;
BlobInfo blob_info = 3;
}
message PutResponse {
@@ -48,12 +48,12 @@ message PutResponse {
bool eosl = 2;
}
message MissingLayersRequest {
string image_id = 1;
repeated string layer_ids = 2;
message MissingBlobsRequest {
string artifact_id = 1;
repeated string blob_ids = 2;
}
message MissingLayersResponse {
bool missing_image = 1;
repeated string missing_layer_ids = 2;
message MissingBlobsResponse {
bool missing_artifact = 1;
repeated string missing_blob_ids = 2;
}

View File

@@ -17,6 +17,7 @@ import fmt "fmt"
import ioutil "io/ioutil"
import http "net/http"
import strconv "strconv"
import gzip "compress/gzip"
import jsonpb "github.com/golang/protobuf/jsonpb"
import proto "github.com/golang/protobuf/proto"
@@ -30,16 +31,19 @@ import io "io"
import json "encoding/json"
import url "net/url"
// A response is compressed with gzip when the response size exceeds this threshold.
const CompressThreshold = 10000
// ===============
// Cache Interface
// ===============
type Cache interface {
PutImage(context.Context, *PutImageRequest) (*google_protobuf1.Empty, error)
PutArtifact(context.Context, *PutArtifactRequest) (*google_protobuf1.Empty, error)
PutLayer(context.Context, *PutLayerRequest) (*google_protobuf1.Empty, error)
PutBlob(context.Context, *PutBlobRequest) (*google_protobuf1.Empty, error)
MissingLayers(context.Context, *MissingLayersRequest) (*MissingLayersResponse, error)
MissingBlobs(context.Context, *MissingBlobsRequest) (*MissingBlobsResponse, error)
}
// =====================
@@ -66,9 +70,9 @@ func NewCacheProtobufClient(addr string, client HTTPClient, opts ...twirp.Client
prefix := urlBase(addr) + CachePathPrefix
urls := [3]string{
prefix + "PutImage",
prefix + "PutLayer",
prefix + "MissingLayers",
prefix + "PutArtifact",
prefix + "PutBlob",
prefix + "MissingBlobs",
}
return &cacheProtobufClient{
@@ -78,10 +82,10 @@ func NewCacheProtobufClient(addr string, client HTTPClient, opts ...twirp.Client
}
}
func (c *cacheProtobufClient) PutImage(ctx context.Context, in *PutImageRequest) (*google_protobuf1.Empty, error) {
func (c *cacheProtobufClient) PutArtifact(ctx context.Context, in *PutArtifactRequest) (*google_protobuf1.Empty, error) {
ctx = ctxsetters.WithPackageName(ctx, "trivy.cache.v1")
ctx = ctxsetters.WithServiceName(ctx, "Cache")
ctx = ctxsetters.WithMethodName(ctx, "PutImage")
ctx = ctxsetters.WithMethodName(ctx, "PutArtifact")
out := new(google_protobuf1.Empty)
err := doProtobufRequest(ctx, c.client, c.opts.Hooks, c.urls[0], in, out)
if err != nil {
@@ -98,10 +102,10 @@ func (c *cacheProtobufClient) PutImage(ctx context.Context, in *PutImageRequest)
return out, nil
}
func (c *cacheProtobufClient) PutLayer(ctx context.Context, in *PutLayerRequest) (*google_protobuf1.Empty, error) {
func (c *cacheProtobufClient) PutBlob(ctx context.Context, in *PutBlobRequest) (*google_protobuf1.Empty, error) {
ctx = ctxsetters.WithPackageName(ctx, "trivy.cache.v1")
ctx = ctxsetters.WithServiceName(ctx, "Cache")
ctx = ctxsetters.WithMethodName(ctx, "PutLayer")
ctx = ctxsetters.WithMethodName(ctx, "PutBlob")
out := new(google_protobuf1.Empty)
err := doProtobufRequest(ctx, c.client, c.opts.Hooks, c.urls[1], in, out)
if err != nil {
@@ -118,11 +122,11 @@ func (c *cacheProtobufClient) PutLayer(ctx context.Context, in *PutLayerRequest)
return out, nil
}
func (c *cacheProtobufClient) MissingLayers(ctx context.Context, in *MissingLayersRequest) (*MissingLayersResponse, error) {
func (c *cacheProtobufClient) MissingBlobs(ctx context.Context, in *MissingBlobsRequest) (*MissingBlobsResponse, error) {
ctx = ctxsetters.WithPackageName(ctx, "trivy.cache.v1")
ctx = ctxsetters.WithServiceName(ctx, "Cache")
ctx = ctxsetters.WithMethodName(ctx, "MissingLayers")
out := new(MissingLayersResponse)
ctx = ctxsetters.WithMethodName(ctx, "MissingBlobs")
out := new(MissingBlobsResponse)
err := doProtobufRequest(ctx, c.client, c.opts.Hooks, c.urls[2], in, out)
if err != nil {
twerr, ok := err.(twirp.Error)
@@ -162,9 +166,9 @@ func NewCacheJSONClient(addr string, client HTTPClient, opts ...twirp.ClientOpti
prefix := urlBase(addr) + CachePathPrefix
urls := [3]string{
prefix + "PutImage",
prefix + "PutLayer",
prefix + "MissingLayers",
prefix + "PutArtifact",
prefix + "PutBlob",
prefix + "MissingBlobs",
}
return &cacheJSONClient{
@@ -174,10 +178,10 @@ func NewCacheJSONClient(addr string, client HTTPClient, opts ...twirp.ClientOpti
}
}
func (c *cacheJSONClient) PutImage(ctx context.Context, in *PutImageRequest) (*google_protobuf1.Empty, error) {
func (c *cacheJSONClient) PutArtifact(ctx context.Context, in *PutArtifactRequest) (*google_protobuf1.Empty, error) {
ctx = ctxsetters.WithPackageName(ctx, "trivy.cache.v1")
ctx = ctxsetters.WithServiceName(ctx, "Cache")
ctx = ctxsetters.WithMethodName(ctx, "PutImage")
ctx = ctxsetters.WithMethodName(ctx, "PutArtifact")
out := new(google_protobuf1.Empty)
err := doJSONRequest(ctx, c.client, c.opts.Hooks, c.urls[0], in, out)
if err != nil {
@@ -194,10 +198,10 @@ func (c *cacheJSONClient) PutImage(ctx context.Context, in *PutImageRequest) (*g
return out, nil
}
func (c *cacheJSONClient) PutLayer(ctx context.Context, in *PutLayerRequest) (*google_protobuf1.Empty, error) {
func (c *cacheJSONClient) PutBlob(ctx context.Context, in *PutBlobRequest) (*google_protobuf1.Empty, error) {
ctx = ctxsetters.WithPackageName(ctx, "trivy.cache.v1")
ctx = ctxsetters.WithServiceName(ctx, "Cache")
ctx = ctxsetters.WithMethodName(ctx, "PutLayer")
ctx = ctxsetters.WithMethodName(ctx, "PutBlob")
out := new(google_protobuf1.Empty)
err := doJSONRequest(ctx, c.client, c.opts.Hooks, c.urls[1], in, out)
if err != nil {
@@ -214,11 +218,11 @@ func (c *cacheJSONClient) PutLayer(ctx context.Context, in *PutLayerRequest) (*g
return out, nil
}
func (c *cacheJSONClient) MissingLayers(ctx context.Context, in *MissingLayersRequest) (*MissingLayersResponse, error) {
func (c *cacheJSONClient) MissingBlobs(ctx context.Context, in *MissingBlobsRequest) (*MissingBlobsResponse, error) {
ctx = ctxsetters.WithPackageName(ctx, "trivy.cache.v1")
ctx = ctxsetters.WithServiceName(ctx, "Cache")
ctx = ctxsetters.WithMethodName(ctx, "MissingLayers")
out := new(MissingLayersResponse)
ctx = ctxsetters.WithMethodName(ctx, "MissingBlobs")
out := new(MissingBlobsResponse)
err := doJSONRequest(ctx, c.client, c.opts.Hooks, c.urls[2], in, out)
if err != nil {
twerr, ok := err.(twirp.Error)
@@ -282,14 +286,14 @@ func (s *cacheServer) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
}
switch req.URL.Path {
case "/twirp/trivy.cache.v1.Cache/PutImage":
s.servePutImage(ctx, resp, req)
case "/twirp/trivy.cache.v1.Cache/PutArtifact":
s.servePutArtifact(ctx, resp, req)
return
case "/twirp/trivy.cache.v1.Cache/PutLayer":
s.servePutLayer(ctx, resp, req)
case "/twirp/trivy.cache.v1.Cache/PutBlob":
s.servePutBlob(ctx, resp, req)
return
case "/twirp/trivy.cache.v1.Cache/MissingLayers":
s.serveMissingLayers(ctx, resp, req)
case "/twirp/trivy.cache.v1.Cache/MissingBlobs":
s.serveMissingBlobs(ctx, resp, req)
return
default:
msg := fmt.Sprintf("no handler for path %q", req.URL.Path)
@@ -299,7 +303,7 @@ func (s *cacheServer) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
}
}
func (s *cacheServer) servePutImage(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
func (s *cacheServer) servePutArtifact(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
header := req.Header.Get("Content-Type")
i := strings.Index(header, ";")
if i == -1 {
@@ -307,9 +311,9 @@ func (s *cacheServer) servePutImage(ctx context.Context, resp http.ResponseWrite
}
switch strings.TrimSpace(strings.ToLower(header[:i])) {
case "application/json":
s.servePutImageJSON(ctx, resp, req)
s.servePutArtifactJSON(ctx, resp, req)
case "application/protobuf":
s.servePutImageProtobuf(ctx, resp, req)
s.servePutArtifactProtobuf(ctx, resp, req)
default:
msg := fmt.Sprintf("unexpected Content-Type: %q", req.Header.Get("Content-Type"))
twerr := badRouteError(msg, req.Method, req.URL.Path)
@@ -317,16 +321,16 @@ func (s *cacheServer) servePutImage(ctx context.Context, resp http.ResponseWrite
}
}
func (s *cacheServer) servePutImageJSON(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
func (s *cacheServer) servePutArtifactJSON(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
var err error
ctx = ctxsetters.WithMethodName(ctx, "PutImage")
ctx = ctxsetters.WithMethodName(ctx, "PutArtifact")
ctx, err = callRequestRouted(ctx, s.hooks)
if err != nil {
s.writeError(ctx, resp, err)
return
}
reqContent := new(PutImageRequest)
reqContent := new(PutArtifactRequest)
unmarshaler := jsonpb.Unmarshaler{AllowUnknownFields: true}
if err = unmarshaler.Unmarshal(req.Body, reqContent); err != nil {
s.writeError(ctx, resp, malformedRequestError("the json request could not be decoded"))
@@ -337,7 +341,7 @@ func (s *cacheServer) servePutImageJSON(ctx context.Context, resp http.ResponseW
var respContent *google_protobuf1.Empty
func() {
defer ensurePanicResponses(ctx, resp, s.hooks)
respContent, err = s.Cache.PutImage(ctx, reqContent)
respContent, err = s.Cache.PutArtifact(ctx, reqContent)
}()
if err != nil {
@@ -345,7 +349,7 @@ func (s *cacheServer) servePutImageJSON(ctx context.Context, resp http.ResponseW
return
}
if respContent == nil {
s.writeError(ctx, resp, twirp.InternalError("received a nil *google_protobuf1.Empty and nil error while calling PutImage. nil responses are not supported"))
s.writeError(ctx, resp, twirp.InternalError("received a nil *google_protobuf1.Empty and nil error while calling PutArtifact. nil responses are not supported"))
return
}
@@ -372,9 +376,9 @@ func (s *cacheServer) servePutImageJSON(ctx context.Context, resp http.ResponseW
callResponseSent(ctx, s.hooks)
}
func (s *cacheServer) servePutImageProtobuf(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
func (s *cacheServer) servePutArtifactProtobuf(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
var err error
ctx = ctxsetters.WithMethodName(ctx, "PutImage")
ctx = ctxsetters.WithMethodName(ctx, "PutArtifact")
ctx, err = callRequestRouted(ctx, s.hooks)
if err != nil {
s.writeError(ctx, resp, err)
@@ -386,7 +390,7 @@ func (s *cacheServer) servePutImageProtobuf(ctx context.Context, resp http.Respo
s.writeError(ctx, resp, wrapInternal(err, "failed to read request body"))
return
}
reqContent := new(PutImageRequest)
reqContent := new(PutArtifactRequest)
if err = proto.Unmarshal(buf, reqContent); err != nil {
s.writeError(ctx, resp, malformedRequestError("the protobuf request could not be decoded"))
return
@@ -396,7 +400,7 @@ func (s *cacheServer) servePutImageProtobuf(ctx context.Context, resp http.Respo
var respContent *google_protobuf1.Empty
func() {
defer ensurePanicResponses(ctx, resp, s.hooks)
respContent, err = s.Cache.PutImage(ctx, reqContent)
respContent, err = s.Cache.PutArtifact(ctx, reqContent)
}()
if err != nil {
@@ -404,7 +408,7 @@ func (s *cacheServer) servePutImageProtobuf(ctx context.Context, resp http.Respo
return
}
if respContent == nil {
s.writeError(ctx, resp, twirp.InternalError("received a nil *google_protobuf1.Empty and nil error while calling PutImage. nil responses are not supported"))
s.writeError(ctx, resp, twirp.InternalError("received a nil *google_protobuf1.Empty and nil error while calling PutArtifact. nil responses are not supported"))
return
}
@@ -416,6 +420,16 @@ func (s *cacheServer) servePutImageProtobuf(ctx context.Context, resp http.Respo
return
}
// Compress the response if the size exceeds the threshold
if len(respBytes) > CompressThreshold && isGZipAcceptable(req) {
respBytes, err = compressWithGzip(respBytes)
if err != nil {
s.writeError(ctx, resp, wrapInternal(err, "failed to compress response"))
return
}
resp.Header().Set("Content-Encoding", "gzip")
}
ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK)
resp.Header().Set("Content-Type", "application/protobuf")
resp.Header().Set("Content-Length", strconv.Itoa(len(respBytes)))
@@ -428,7 +442,7 @@ func (s *cacheServer) servePutImageProtobuf(ctx context.Context, resp http.Respo
callResponseSent(ctx, s.hooks)
}
func (s *cacheServer) servePutLayer(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
func (s *cacheServer) servePutBlob(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
header := req.Header.Get("Content-Type")
i := strings.Index(header, ";")
if i == -1 {
@@ -436,9 +450,9 @@ func (s *cacheServer) servePutLayer(ctx context.Context, resp http.ResponseWrite
}
switch strings.TrimSpace(strings.ToLower(header[:i])) {
case "application/json":
s.servePutLayerJSON(ctx, resp, req)
s.servePutBlobJSON(ctx, resp, req)
case "application/protobuf":
s.servePutLayerProtobuf(ctx, resp, req)
s.servePutBlobProtobuf(ctx, resp, req)
default:
msg := fmt.Sprintf("unexpected Content-Type: %q", req.Header.Get("Content-Type"))
twerr := badRouteError(msg, req.Method, req.URL.Path)
@@ -446,16 +460,16 @@ func (s *cacheServer) servePutLayer(ctx context.Context, resp http.ResponseWrite
}
}
func (s *cacheServer) servePutLayerJSON(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
func (s *cacheServer) servePutBlobJSON(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
var err error
ctx = ctxsetters.WithMethodName(ctx, "PutLayer")
ctx = ctxsetters.WithMethodName(ctx, "PutBlob")
ctx, err = callRequestRouted(ctx, s.hooks)
if err != nil {
s.writeError(ctx, resp, err)
return
}
reqContent := new(PutLayerRequest)
reqContent := new(PutBlobRequest)
unmarshaler := jsonpb.Unmarshaler{AllowUnknownFields: true}
if err = unmarshaler.Unmarshal(req.Body, reqContent); err != nil {
s.writeError(ctx, resp, malformedRequestError("the json request could not be decoded"))
@@ -466,7 +480,7 @@ func (s *cacheServer) servePutLayerJSON(ctx context.Context, resp http.ResponseW
var respContent *google_protobuf1.Empty
func() {
defer ensurePanicResponses(ctx, resp, s.hooks)
respContent, err = s.Cache.PutLayer(ctx, reqContent)
respContent, err = s.Cache.PutBlob(ctx, reqContent)
}()
if err != nil {
@@ -474,7 +488,7 @@ func (s *cacheServer) servePutLayerJSON(ctx context.Context, resp http.ResponseW
return
}
if respContent == nil {
s.writeError(ctx, resp, twirp.InternalError("received a nil *google_protobuf1.Empty and nil error while calling PutLayer. nil responses are not supported"))
s.writeError(ctx, resp, twirp.InternalError("received a nil *google_protobuf1.Empty and nil error while calling PutBlob. nil responses are not supported"))
return
}
@@ -501,9 +515,9 @@ func (s *cacheServer) servePutLayerJSON(ctx context.Context, resp http.ResponseW
callResponseSent(ctx, s.hooks)
}
func (s *cacheServer) servePutLayerProtobuf(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
func (s *cacheServer) servePutBlobProtobuf(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
var err error
ctx = ctxsetters.WithMethodName(ctx, "PutLayer")
ctx = ctxsetters.WithMethodName(ctx, "PutBlob")
ctx, err = callRequestRouted(ctx, s.hooks)
if err != nil {
s.writeError(ctx, resp, err)
@@ -515,7 +529,7 @@ func (s *cacheServer) servePutLayerProtobuf(ctx context.Context, resp http.Respo
s.writeError(ctx, resp, wrapInternal(err, "failed to read request body"))
return
}
reqContent := new(PutLayerRequest)
reqContent := new(PutBlobRequest)
if err = proto.Unmarshal(buf, reqContent); err != nil {
s.writeError(ctx, resp, malformedRequestError("the protobuf request could not be decoded"))
return
@@ -525,7 +539,7 @@ func (s *cacheServer) servePutLayerProtobuf(ctx context.Context, resp http.Respo
var respContent *google_protobuf1.Empty
func() {
defer ensurePanicResponses(ctx, resp, s.hooks)
respContent, err = s.Cache.PutLayer(ctx, reqContent)
respContent, err = s.Cache.PutBlob(ctx, reqContent)
}()
if err != nil {
@@ -533,7 +547,7 @@ func (s *cacheServer) servePutLayerProtobuf(ctx context.Context, resp http.Respo
return
}
if respContent == nil {
s.writeError(ctx, resp, twirp.InternalError("received a nil *google_protobuf1.Empty and nil error while calling PutLayer. nil responses are not supported"))
s.writeError(ctx, resp, twirp.InternalError("received a nil *google_protobuf1.Empty and nil error while calling PutBlob. nil responses are not supported"))
return
}
@@ -545,6 +559,16 @@ func (s *cacheServer) servePutLayerProtobuf(ctx context.Context, resp http.Respo
return
}
// Compress the response if the size exceeds the threshold
if len(respBytes) > CompressThreshold && isGZipAcceptable(req) {
respBytes, err = compressWithGzip(respBytes)
if err != nil {
s.writeError(ctx, resp, wrapInternal(err, "failed to compress response"))
return
}
resp.Header().Set("Content-Encoding", "gzip")
}
ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK)
resp.Header().Set("Content-Type", "application/protobuf")
resp.Header().Set("Content-Length", strconv.Itoa(len(respBytes)))
@@ -557,7 +581,7 @@ func (s *cacheServer) servePutLayerProtobuf(ctx context.Context, resp http.Respo
callResponseSent(ctx, s.hooks)
}
func (s *cacheServer) serveMissingLayers(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
func (s *cacheServer) serveMissingBlobs(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
header := req.Header.Get("Content-Type")
i := strings.Index(header, ";")
if i == -1 {
@@ -565,9 +589,9 @@ func (s *cacheServer) serveMissingLayers(ctx context.Context, resp http.Response
}
switch strings.TrimSpace(strings.ToLower(header[:i])) {
case "application/json":
s.serveMissingLayersJSON(ctx, resp, req)
s.serveMissingBlobsJSON(ctx, resp, req)
case "application/protobuf":
s.serveMissingLayersProtobuf(ctx, resp, req)
s.serveMissingBlobsProtobuf(ctx, resp, req)
default:
msg := fmt.Sprintf("unexpected Content-Type: %q", req.Header.Get("Content-Type"))
twerr := badRouteError(msg, req.Method, req.URL.Path)
@@ -575,16 +599,16 @@ func (s *cacheServer) serveMissingLayers(ctx context.Context, resp http.Response
}
}
func (s *cacheServer) serveMissingLayersJSON(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
func (s *cacheServer) serveMissingBlobsJSON(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
var err error
ctx = ctxsetters.WithMethodName(ctx, "MissingLayers")
ctx = ctxsetters.WithMethodName(ctx, "MissingBlobs")
ctx, err = callRequestRouted(ctx, s.hooks)
if err != nil {
s.writeError(ctx, resp, err)
return
}
reqContent := new(MissingLayersRequest)
reqContent := new(MissingBlobsRequest)
unmarshaler := jsonpb.Unmarshaler{AllowUnknownFields: true}
if err = unmarshaler.Unmarshal(req.Body, reqContent); err != nil {
s.writeError(ctx, resp, malformedRequestError("the json request could not be decoded"))
@@ -592,10 +616,10 @@ func (s *cacheServer) serveMissingLayersJSON(ctx context.Context, resp http.Resp
}
// Call service method
var respContent *MissingLayersResponse
var respContent *MissingBlobsResponse
func() {
defer ensurePanicResponses(ctx, resp, s.hooks)
respContent, err = s.Cache.MissingLayers(ctx, reqContent)
respContent, err = s.Cache.MissingBlobs(ctx, reqContent)
}()
if err != nil {
@@ -603,7 +627,7 @@ func (s *cacheServer) serveMissingLayersJSON(ctx context.Context, resp http.Resp
return
}
if respContent == nil {
s.writeError(ctx, resp, twirp.InternalError("received a nil *MissingLayersResponse and nil error while calling MissingLayers. nil responses are not supported"))
s.writeError(ctx, resp, twirp.InternalError("received a nil *MissingBlobsResponse and nil error while calling MissingBlobs. nil responses are not supported"))
return
}
@@ -630,9 +654,9 @@ func (s *cacheServer) serveMissingLayersJSON(ctx context.Context, resp http.Resp
callResponseSent(ctx, s.hooks)
}
func (s *cacheServer) serveMissingLayersProtobuf(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
func (s *cacheServer) serveMissingBlobsProtobuf(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
var err error
ctx = ctxsetters.WithMethodName(ctx, "MissingLayers")
ctx = ctxsetters.WithMethodName(ctx, "MissingBlobs")
ctx, err = callRequestRouted(ctx, s.hooks)
if err != nil {
s.writeError(ctx, resp, err)
@@ -644,17 +668,17 @@ func (s *cacheServer) serveMissingLayersProtobuf(ctx context.Context, resp http.
s.writeError(ctx, resp, wrapInternal(err, "failed to read request body"))
return
}
reqContent := new(MissingLayersRequest)
reqContent := new(MissingBlobsRequest)
if err = proto.Unmarshal(buf, reqContent); err != nil {
s.writeError(ctx, resp, malformedRequestError("the protobuf request could not be decoded"))
return
}
// Call service method
var respContent *MissingLayersResponse
var respContent *MissingBlobsResponse
func() {
defer ensurePanicResponses(ctx, resp, s.hooks)
respContent, err = s.Cache.MissingLayers(ctx, reqContent)
respContent, err = s.Cache.MissingBlobs(ctx, reqContent)
}()
if err != nil {
@@ -662,7 +686,7 @@ func (s *cacheServer) serveMissingLayersProtobuf(ctx context.Context, resp http.
return
}
if respContent == nil {
s.writeError(ctx, resp, twirp.InternalError("received a nil *MissingLayersResponse and nil error while calling MissingLayers. nil responses are not supported"))
s.writeError(ctx, resp, twirp.InternalError("received a nil *MissingBlobsResponse and nil error while calling MissingBlobs. nil responses are not supported"))
return
}
@@ -674,6 +698,16 @@ func (s *cacheServer) serveMissingLayersProtobuf(ctx context.Context, resp http.
return
}
// Compress the response if the size exceeds the threshold
if len(respBytes) > CompressThreshold && isGZipAcceptable(req) {
respBytes, err = compressWithGzip(respBytes)
if err != nil {
s.writeError(ctx, resp, wrapInternal(err, "failed to compress response"))
return
}
resp.Header().Set("Content-Encoding", "gzip")
}
ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK)
resp.Header().Set("Content-Type", "application/protobuf")
resp.Header().Set("Content-Length", strconv.Itoa(len(respBytes)))
@@ -832,6 +866,7 @@ func newRequest(ctx context.Context, url string, reqBody io.Reader, contentType
}
req.Header.Set("Accept", contentType)
req.Header.Set("Content-Type", contentType)
req.Header.Set("Accept-Encoding", "gzip")
req.Header.Set("Twirp-Version", "v5.10.1")
return req, nil
}
@@ -1084,7 +1119,15 @@ func doProtobufRequest(ctx context.Context, client HTTPClient, hooks *twirp.Clie
return errorFromResponse(resp)
}
respBodyBytes, err := ioutil.ReadAll(resp.Body)
r := resp.Body
if resp.Header.Get("Content-Encoding") == "gzip" {
r, err = gzip.NewReader(r)
if err != nil {
return wrapInternal(err, "invalid gzip")
}
}
respBodyBytes, err := ioutil.ReadAll(r)
if err != nil {
return wrapInternal(err, "failed to read response body")
}
@@ -1189,6 +1232,36 @@ func callError(ctx context.Context, h *twirp.ServerHooks, err twirp.Error) conte
return h.Error(ctx, err)
}
// compressWithGzip compresses the data with gzip
func compressWithGzip(data []byte) ([]byte, error) {
var b bytes.Buffer
gz := gzip.NewWriter(&b)
defer gz.Close()
if _, err := gz.Write(data); err != nil {
return nil, err
}
if err := gz.Flush(); err != nil {
return nil, err
}
if err := gz.Close(); err != nil {
return nil, err
}
return b.Bytes(), nil
}
func isGZipAcceptable(request *http.Request) bool {
for _, encoding := range request.Header["Accept-Encoding"] {
if encoding == "gzip" {
return true
}
}
return false
}
func callClientResponseReceived(ctx context.Context, h *twirp.ClientHooks) {
if h == nil || h.ResponseReceived == nil {
return
@@ -1211,48 +1284,48 @@ func callClientError(ctx context.Context, h *twirp.ClientHooks, err twirp.Error)
}
var twirpFileDescriptor0 = []byte{
// 674 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0xdd, 0x6e, 0xd3, 0x30,
0x14, 0x56, 0xdb, 0x75, 0x6d, 0x4e, 0xdb, 0x6d, 0x58, 0x6c, 0xcb, 0xba, 0x8b, 0x55, 0x81, 0x49,
0x15, 0x17, 0x89, 0x28, 0x08, 0x71, 0x03, 0x02, 0x06, 0x48, 0x95, 0xf8, 0x99, 0x0c, 0xe2, 0x02,
0x21, 0x55, 0x5e, 0xe2, 0xa4, 0xd6, 0x9a, 0x38, 0xb3, 0x9d, 0xa2, 0x3e, 0x00, 0x6f, 0xc7, 0xbb,
0xf0, 0x0a, 0x28, 0x27, 0xc9, 0xd6, 0x96, 0xf2, 0x77, 0xe7, 0xf3, 0x93, 0xef, 0x7c, 0xe7, 0xfb,
0xec, 0xc0, 0xa1, 0x4a, 0x7d, 0xcf, 0x67, 0xfe, 0x94, 0x7b, 0x9a, 0xab, 0xb9, 0xf0, 0xb9, 0x9b,
0x2a, 0x69, 0x24, 0xd9, 0x31, 0x4a, 0xcc, 0x17, 0x2e, 0x96, 0xdc, 0xf9, 0xfd, 0xfe, 0x49, 0x24,
0x65, 0x34, 0xe3, 0x1e, 0x56, 0x2f, 0xb2, 0xd0, 0x33, 0x22, 0xe6, 0xda, 0xb0, 0x38, 0x2d, 0x3e,
0xe8, 0x3f, 0x8a, 0x84, 0x99, 0x66, 0x17, 0xae, 0x2f, 0x63, 0x8f, 0x5d, 0x65, 0x4c, 0x73, 0x3f,
0x53, 0xc2, 0x2c, 0x3c, 0x04, 0xf2, 0x70, 0x8e, 0x8c, 0x63, 0x99, 0xac, 0x0e, 0xea, 0x1f, 0xaf,
0x03, 0xf3, 0x38, 0x35, 0x8b, 0xa2, 0xe8, 0x7c, 0xab, 0x83, 0x35, 0x8e, 0x59, 0xc4, 0xc7, 0x49,
0x28, 0xc9, 0x29, 0xec, 0x68, 0x7f, 0xca, 0x63, 0x36, 0x99, 0x73, 0xa5, 0x85, 0x4c, 0xec, 0xda,
0xa0, 0x36, 0x6c, 0xd2, 0x5e, 0x91, 0xfd, 0x54, 0x24, 0x89, 0x03, 0x5d, 0xa6, 0xfc, 0xa9, 0x30,
0xdc, 0x37, 0x99, 0xe2, 0x76, 0x7d, 0x50, 0x1b, 0x5a, 0x74, 0x25, 0x47, 0x1e, 0x42, 0xcb, 0x57,
0x9c, 0x19, 0x1e, 0xd8, 0x8d, 0x41, 0x6d, 0xd8, 0x19, 0xf5, 0xdd, 0x82, 0x87, 0x5b, 0xf1, 0x70,
0x3f, 0x56, 0x0b, 0xd2, 0xaa, 0x35, 0x27, 0x10, 0x48, 0xff, 0x92, 0xab, 0x6b, 0x02, 0x5b, 0x88,
0xdd, 0x2b, 0xb2, 0x15, 0x81, 0x1d, 0xa8, 0x4b, 0x6d, 0x37, 0xb1, 0x54, 0x97, 0x9a, 0x3c, 0x83,
0xbd, 0xa9, 0xd0, 0x46, 0xaa, 0xc5, 0x24, 0x65, 0xfe, 0x25, 0x8b, 0xb8, 0xb6, 0xb7, 0x07, 0x8d,
0x61, 0x67, 0xb4, 0xef, 0x96, 0x32, 0xa3, 0x32, 0xee, 0x79, 0x51, 0xa5, 0xbb, 0x65, 0x7b, 0x19,
0x6b, 0x27, 0x84, 0xdd, 0xf3, 0xcc, 0xa0, 0x12, 0x94, 0x5f, 0x65, 0x5c, 0x1b, 0x72, 0x04, 0x6d,
0x91, 0xc7, 0x13, 0x11, 0xa0, 0x0c, 0x16, 0x6d, 0x61, 0x3c, 0x0e, 0xc8, 0x63, 0x80, 0xb2, 0x94,
0x84, 0x12, 0xd7, 0xef, 0x8c, 0x8e, 0xdc, 0x55, 0x43, 0xdd, 0x6b, 0x59, 0xa9, 0x25, 0xaa, 0xa3,
0xf3, 0xbd, 0x0e, 0xd6, 0x1b, 0xb6, 0xe0, 0xea, 0x7f, 0xf4, 0x1e, 0xe0, 0xba, 0xc5, 0x98, 0xbd,
0xd5, 0x85, 0xde, 0x7f, 0x40, 0x01, 0x9e, 0x42, 0xaf, 0x5c, 0x1c, 0x29, 0x69, 0xbb, 0x81, 0xdb,
0x1f, 0x6d, 0xdc, 0x1e, 0x39, 0x75, 0xd3, 0x9b, 0x40, 0x93, 0x27, 0xd0, 0x65, 0x69, 0x3a, 0x13,
0x3e, 0x33, 0x42, 0x26, 0xda, 0xde, 0xda, 0xf4, 0xf9, 0xf3, 0x9b, 0x0e, 0xba, 0xd2, 0x4e, 0x4e,
0xa0, 0x23, 0x53, 0x76, 0x95, 0xf1, 0x49, 0x20, 0x54, 0x6e, 0x4c, 0x63, 0x68, 0x51, 0x28, 0x52,
0x2f, 0x85, 0xd2, 0xf9, 0xa2, 0x5f, 0xf3, 0xbb, 0x21, 0x33, 0x33, 0x09, 0xc5, 0xac, 0xb4, 0xc7,
0xa2, 0xbd, 0x2a, 0xfb, 0x3a, 0x4f, 0x92, 0x03, 0xd8, 0x0e, 0x44, 0xc4, 0xb5, 0xb1, 0x5b, 0x28,
0x78, 0x19, 0x91, 0x43, 0x68, 0x05, 0x22, 0x0c, 0x73, 0x27, 0xda, 0x55, 0x21, 0x0c, 0xc7, 0x81,
0x13, 0xa0, 0x6d, 0x28, 0x68, 0x65, 0xdb, 0x52, 0x6f, 0x6d, 0xb9, 0x37, 0x37, 0x6d, 0x96, 0x37,
0x16, 0xa6, 0x35, 0x36, 0x9b, 0x76, 0xed, 0x0d, 0xb5, 0x66, 0xd5, 0xd1, 0x39, 0x83, 0xce, 0x79,
0x66, 0x28, 0xd7, 0xa9, 0x4c, 0x34, 0x2f, 0xed, 0xa8, 0xfd, 0xc1, 0x0e, 0x02, 0x5b, 0x5c, 0xea,
0x19, 0x5a, 0xd6, 0xa6, 0x78, 0x76, 0xde, 0xc1, 0xed, 0xb7, 0x42, 0x6b, 0x91, 0x44, 0x38, 0x43,
0xff, 0xc3, 0x35, 0x3b, 0x06, 0xab, 0x64, 0x1c, 0xe4, 0xf6, 0xe7, 0x82, 0xb5, 0x0b, 0x56, 0x81,
0x76, 0xa6, 0xb0, 0xbf, 0x86, 0x57, 0xd2, 0xbb, 0x03, 0xbd, 0xb8, 0x28, 0x4c, 0x10, 0x08, 0x51,
0xdb, 0xb4, 0x5b, 0x26, 0xf1, 0x5a, 0x92, 0x7b, 0x70, 0xab, 0x6a, 0x5a, 0x1f, 0xb1, 0x1b, 0x2f,
0xc1, 0x8e, 0x03, 0x3d, 0xfa, 0x51, 0x83, 0xe6, 0x59, 0x2e, 0x10, 0x39, 0x83, 0x76, 0xf5, 0x4a,
0xc8, 0xc9, 0xba, 0x74, 0x6b, 0xef, 0xa7, 0x7f, 0xf0, 0xcb, 0x83, 0x7f, 0x95, 0xff, 0x78, 0x4a,
0x10, 0x44, 0xdf, 0x08, 0xb2, 0xec, 0xe6, 0x6f, 0x41, 0xbe, 0x40, 0x6f, 0x65, 0x7b, 0x72, 0x77,
0x1d, 0x69, 0x93, 0xd8, 0xfd, 0xd3, 0xbf, 0x74, 0x15, 0x12, 0xbe, 0x68, 0x7d, 0x6e, 0x62, 0xc7,
0xc5, 0x36, 0x8e, 0x7d, 0xf0, 0x33, 0x00, 0x00, 0xff, 0xff, 0x08, 0x8d, 0x6f, 0x9e, 0xc6, 0x05,
0x00, 0x00,
// 682 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x94, 0xdd, 0x6e, 0xd3, 0x3e,
0x18, 0xc6, 0xd5, 0x76, 0x5d, 0xdb, 0xb7, 0x1f, 0x9b, 0xfc, 0xff, 0xb3, 0x65, 0x05, 0xb1, 0x2a,
0x80, 0x54, 0x4e, 0x52, 0x51, 0x3e, 0xce, 0x40, 0x74, 0x03, 0xa4, 0x1e, 0x20, 0x4a, 0x40, 0x48,
0x70, 0x52, 0x5c, 0xc7, 0x69, 0xad, 0x35, 0x71, 0x66, 0x3b, 0x85, 0xde, 0x01, 0xf7, 0xc6, 0xcd,
0x70, 0x09, 0xc8, 0x76, 0xb2, 0x7e, 0xac, 0x4c, 0x70, 0x16, 0x3f, 0x7e, 0xf3, 0xbc, 0xaf, 0x7f,
0x8f, 0x13, 0x38, 0x16, 0x09, 0xe9, 0x11, 0x4c, 0x66, 0xb4, 0x27, 0xa9, 0x58, 0x30, 0x42, 0xbd,
0x44, 0x70, 0xc5, 0x51, 0x4b, 0x09, 0xb6, 0x58, 0x7a, 0x66, 0xcb, 0x5b, 0x3c, 0x6a, 0x9f, 0x4e,
0x39, 0x9f, 0xce, 0x69, 0xcf, 0xec, 0x4e, 0xd2, 0xb0, 0xa7, 0x58, 0x44, 0xa5, 0xc2, 0x51, 0x62,
0x5f, 0x68, 0x3f, 0x9b, 0x32, 0x35, 0x4b, 0x27, 0x1e, 0xe1, 0x51, 0x0f, 0x5f, 0xa6, 0x58, 0x52,
0x92, 0x0a, 0xa6, 0x96, 0x3d, 0x63, 0xd4, 0x33, 0x7d, 0x78, 0x14, 0xf1, 0x78, 0xb3, 0x51, 0xfb,
0xf6, 0xb6, 0x31, 0x8d, 0x12, 0xb5, 0xb4, 0x9b, 0xee, 0x8f, 0x22, 0x34, 0x06, 0x42, 0xb1, 0x10,
0x13, 0x35, 0x8c, 0x43, 0x8e, 0x1e, 0x40, 0x4b, 0x92, 0x19, 0x8d, 0xf0, 0x78, 0x41, 0x85, 0x64,
0x3c, 0x76, 0x0a, 0x9d, 0x42, 0xb7, 0xec, 0x37, 0xad, 0xfa, 0xc9, 0x8a, 0xc8, 0x85, 0x06, 0x16,
0x64, 0xc6, 0x14, 0x25, 0x2a, 0x15, 0xd4, 0x29, 0x76, 0x0a, 0xdd, 0x9a, 0xbf, 0xa1, 0xa1, 0x27,
0x50, 0x21, 0x82, 0x62, 0x45, 0x03, 0xa7, 0xd4, 0x29, 0x74, 0xeb, 0xfd, 0xb6, 0x67, 0x47, 0xf1,
0xf2, 0x51, 0xbc, 0x8f, 0xf9, 0x19, 0xfd, 0xbc, 0x54, 0x0f, 0x10, 0x70, 0x72, 0x41, 0xc5, 0xd5,
0x00, 0x7b, 0xc6, 0xbb, 0x69, 0xd5, 0x7c, 0x80, 0x16, 0x14, 0xb9, 0x74, 0xca, 0x66, 0xab, 0xc8,
0x25, 0x7a, 0x09, 0x87, 0x33, 0x26, 0x15, 0x17, 0xcb, 0x71, 0x82, 0xc9, 0x05, 0x9e, 0x52, 0xe9,
0xec, 0x77, 0x4a, 0xdd, 0x7a, 0xff, 0x96, 0x97, 0x91, 0x36, 0x70, 0xbc, 0x91, 0xdd, 0xf5, 0x0f,
0xb2, 0xf2, 0x6c, 0x2d, 0xdd, 0xef, 0x80, 0x46, 0xa9, 0xca, 0x61, 0xf8, 0xf4, 0x32, 0xa5, 0x52,
0xa1, 0x53, 0xa8, 0xe3, 0x4c, 0x1a, 0xb3, 0xc0, 0xc0, 0xa8, 0xf9, 0x90, 0x4b, 0xc3, 0x00, 0x0d,
0xa0, 0xb9, 0x2a, 0x88, 0x43, 0x6e, 0x50, 0xd4, 0xfb, 0x77, 0xbc, 0xcd, 0x7c, 0xbd, 0x75, 0xca,
0x1a, 0xd4, 0x6a, 0xe5, 0xfe, 0x2c, 0x42, 0xf5, 0x6c, 0xce, 0x27, 0xff, 0x12, 0x40, 0xc7, 0x9c,
0xdf, 0xf6, 0x3a, 0xdc, 0x3c, 0xe1, 0xbb, 0x0f, 0x86, 0xc8, 0x0b, 0x68, 0x66, 0x24, 0xcc, 0x5c,
0xd2, 0x29, 0x19, 0x1c, 0x27, 0x3b, 0x71, 0xd8, 0xa9, 0x92, 0xd5, 0x42, 0xa2, 0xe7, 0xd0, 0xc0,
0x49, 0x32, 0x67, 0x04, 0x2b, 0xc6, 0x63, 0xe9, 0xec, 0xed, 0x7a, 0x7d, 0xb0, 0xaa, 0xf0, 0x37,
0xca, 0x35, 0x38, 0x9e, 0xe0, 0xcb, 0x94, 0x8e, 0x03, 0x26, 0x74, 0x52, 0x25, 0x0d, 0xce, 0x4a,
0xaf, 0x98, 0x90, 0xfa, 0xa0, 0xdf, 0xf4, 0x65, 0xe1, 0xa9, 0x1a, 0x87, 0x6c, 0x9e, 0xe5, 0x55,
0xf3, 0x9b, 0xb9, 0xfa, 0x46, 0x8b, 0xe8, 0x08, 0xf6, 0x03, 0x36, 0xa5, 0x52, 0x39, 0x15, 0xc3,
0x3e, 0x5b, 0xa1, 0x63, 0xa8, 0x04, 0x2c, 0x0c, 0x75, 0x28, 0xd5, 0x7c, 0x23, 0x0c, 0x87, 0x81,
0xfb, 0x15, 0x5a, 0xa3, 0x54, 0x69, 0x9e, 0x79, 0x86, 0x6b, 0xa5, 0x85, 0xf5, 0x52, 0xf4, 0x14,
0x6a, 0x93, 0x39, 0x9f, 0xd8, 0xdc, 0xec, 0x1d, 0x75, 0xb6, 0x73, 0xcb, 0x83, 0xf1, 0xab, 0x93,
0xec, 0xc9, 0x3d, 0x87, 0xfa, 0x28, 0x55, 0x3e, 0x95, 0x09, 0x8f, 0x25, 0xcd, 0xa2, 0x28, 0xdc,
0x10, 0x05, 0x82, 0x3d, 0xca, 0xe5, 0xdc, 0xc4, 0x55, 0xf5, 0xcd, 0xb3, 0xfb, 0x1e, 0xfe, 0x7b,
0xcb, 0xa4, 0x64, 0xf1, 0x54, 0x77, 0x90, 0x7f, 0x7d, 0xdf, 0x4e, 0xa0, 0x6a, 0x67, 0x0e, 0x74,
0xfc, 0x1a, 0x58, 0xc5, 0x0c, 0x16, 0x48, 0xf7, 0x02, 0xfe, 0xdf, 0xb4, 0xcc, 0x06, 0x7c, 0x08,
0x87, 0x91, 0xd5, 0xc7, 0xb9, 0x91, 0x31, 0xae, 0xfa, 0x07, 0x99, 0x9e, 0x5f, 0x4e, 0xd4, 0x5d,
0x95, 0x6e, 0x75, 0x69, 0x45, 0x2b, 0xeb, 0x61, 0x20, 0xfb, 0xbf, 0x0a, 0x50, 0x3e, 0xd7, 0x90,
0xd0, 0xd0, 0xe0, 0xb8, 0xb2, 0x70, 0xb7, 0x09, 0x5e, 0xff, 0xaa, 0xda, 0x47, 0xd7, 0xfe, 0x04,
0xaf, 0xf5, 0x4f, 0x09, 0x0d, 0xa0, 0x92, 0x65, 0x87, 0xee, 0xee, 0xb0, 0x59, 0x0b, 0xf5, 0x8f,
0x16, 0x9f, 0xa1, 0xb1, 0x0e, 0x01, 0xdd, 0xdb, 0xf6, 0xd9, 0x41, 0xbd, 0x7d, 0xff, 0xe6, 0x22,
0xcb, 0xf1, 0xac, 0xf2, 0xa5, 0x6c, 0x0a, 0x26, 0xfb, 0xa6, 0xe7, 0xe3, 0xdf, 0x01, 0x00, 0x00,
0xff, 0xff, 0xf9, 0x1a, 0xc0, 0xa0, 0xdd, 0x05, 0x00, 0x00,
}

View File

@@ -17,6 +17,7 @@ import fmt "fmt"
import ioutil "io/ioutil"
import http "net/http"
import strconv "strconv"
import gzip "compress/gzip"
import jsonpb "github.com/golang/protobuf/jsonpb"
import proto "github.com/golang/protobuf/proto"
@@ -28,6 +29,9 @@ import io "io"
import json "encoding/json"
import url "net/url"
// A response is compressed with gzip when the response size exceeds this threshold.
const CompressThreshold = 10000
// ====================
// OSDetector Interface
// ====================
@@ -320,6 +324,16 @@ func (s *oSDetectorServer) serveDetectProtobuf(ctx context.Context, resp http.Re
return
}
// Compress the response if the size exceeds the threshold
if len(respBytes) > CompressThreshold && isGZipAcceptable(req) {
respBytes, err = compressWithGzip(respBytes)
if err != nil {
s.writeError(ctx, resp, wrapInternal(err, "failed to compress response"))
return
}
resp.Header().Set("Content-Encoding", "gzip")
}
ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK)
resp.Header().Set("Content-Type", "application/protobuf")
resp.Header().Set("Content-Length", strconv.Itoa(len(respBytes)))
@@ -636,6 +650,16 @@ func (s *libDetectorServer) serveDetectProtobuf(ctx context.Context, resp http.R
return
}
// Compress the response if the size exceeds the threshold
if len(respBytes) > CompressThreshold && isGZipAcceptable(req) {
respBytes, err = compressWithGzip(respBytes)
if err != nil {
s.writeError(ctx, resp, wrapInternal(err, "failed to compress response"))
return
}
resp.Header().Set("Content-Encoding", "gzip")
}
ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK)
resp.Header().Set("Content-Type", "application/protobuf")
resp.Header().Set("Content-Length", strconv.Itoa(len(respBytes)))
@@ -794,6 +818,7 @@ func newRequest(ctx context.Context, url string, reqBody io.Reader, contentType
}
req.Header.Set("Accept", contentType)
req.Header.Set("Content-Type", contentType)
req.Header.Set("Accept-Encoding", "gzip")
req.Header.Set("Twirp-Version", "v5.10.1")
return req, nil
}
@@ -1046,7 +1071,15 @@ func doProtobufRequest(ctx context.Context, client HTTPClient, hooks *twirp.Clie
return errorFromResponse(resp)
}
respBodyBytes, err := ioutil.ReadAll(resp.Body)
r := resp.Body
if resp.Header.Get("Content-Encoding") == "gzip" {
r, err = gzip.NewReader(r)
if err != nil {
return wrapInternal(err, "invalid gzip")
}
}
respBodyBytes, err := ioutil.ReadAll(r)
if err != nil {
return wrapInternal(err, "failed to read response body")
}
@@ -1151,6 +1184,36 @@ func callError(ctx context.Context, h *twirp.ServerHooks, err twirp.Error) conte
return h.Error(ctx, err)
}
// compressWithGzip compresses the data with gzip
func compressWithGzip(data []byte) ([]byte, error) {
var b bytes.Buffer
gz := gzip.NewWriter(&b)
defer gz.Close()
if _, err := gz.Write(data); err != nil {
return nil, err
}
if err := gz.Flush(); err != nil {
return nil, err
}
if err := gz.Close(); err != nil {
return nil, err
}
return b.Bytes(), nil
}
func isGZipAcceptable(request *http.Request) bool {
for _, encoding := range request.Header["Accept-Encoding"] {
if encoding == "gzip" {
return true
}
}
return false
}
func callClientResponseReceived(ctx context.Context, h *twirp.ClientHooks) {
if h == nil || h.ResponseReceived == nil {
return

View File

@@ -23,8 +23,8 @@ const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type ScanRequest struct {
Target string `protobuf:"bytes,1,opt,name=target,proto3" json:"target,omitempty"`
ImageId string `protobuf:"bytes,2,opt,name=image_id,json=imageId,proto3" json:"image_id,omitempty"`
LayerIds []string `protobuf:"bytes,3,rep,name=layer_ids,json=layerIds,proto3" json:"layer_ids,omitempty"`
ArtifactId string `protobuf:"bytes,2,opt,name=artifact_id,json=artifactId,proto3" json:"artifact_id,omitempty"`
BlobIds []string `protobuf:"bytes,3,rep,name=blob_ids,json=blobIds,proto3" json:"blob_ids,omitempty"`
Options *ScanOptions `protobuf:"bytes,4,opt,name=options,proto3" json:"options,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
@@ -63,16 +63,16 @@ func (m *ScanRequest) GetTarget() string {
return ""
}
func (m *ScanRequest) GetImageId() string {
func (m *ScanRequest) GetArtifactId() string {
if m != nil {
return m.ImageId
return m.ArtifactId
}
return ""
}
func (m *ScanRequest) GetLayerIds() []string {
func (m *ScanRequest) GetBlobIds() []string {
if m != nil {
return m.LayerIds
return m.BlobIds
}
return nil
}
@@ -244,28 +244,29 @@ func init() {
func init() { proto.RegisterFile("rpc/scanner/service.proto", fileDescriptor_60d0e837512b18d4) }
var fileDescriptor_60d0e837512b18d4 = []byte{
// 367 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x52, 0x4d, 0x6b, 0x83, 0x30,
0x18, 0x46, 0x5b, 0x6a, 0x8d, 0x83, 0x95, 0x1c, 0x86, 0x6d, 0xd9, 0x10, 0x4f, 0x65, 0x07, 0x65,
0x0e, 0xb6, 0xfb, 0xa0, 0x87, 0x9e, 0x3a, 0xd2, 0xb1, 0xc3, 0x2e, 0x25, 0xd5, 0x97, 0x2e, 0xa0,
0xc6, 0x26, 0x51, 0x26, 0xfb, 0x1f, 0xfb, 0xbd, 0xc3, 0xc4, 0xc2, 0xda, 0xd1, 0xdb, 0xfb, 0xf1,
0xf8, 0x7c, 0xbc, 0x06, 0x4d, 0x45, 0x95, 0xc6, 0x32, 0xa5, 0x65, 0x09, 0x22, 0x96, 0x20, 0x1a,
0x96, 0x42, 0x54, 0x09, 0xae, 0x38, 0x9e, 0x28, 0xc1, 0x9a, 0x36, 0xea, 0x97, 0x51, 0xf3, 0x30,
0x7b, 0xda, 0x33, 0xf5, 0x59, 0xef, 0xa2, 0x94, 0x17, 0x31, 0x3d, 0xd4, 0x54, 0x42, 0x5a, 0x0b,
0xa6, 0xda, 0x58, 0x23, 0xe3, 0x8e, 0x2a, 0xe5, 0x45, 0xc1, 0xcb, 0x53, 0xa6, 0xf0, 0xc7, 0x42,
0xde, 0x26, 0xa5, 0x25, 0x81, 0x43, 0x0d, 0x52, 0xe1, 0x1b, 0x34, 0x52, 0x54, 0xec, 0x41, 0xf9,
0x56, 0x60, 0x2d, 0x5c, 0xd2, 0x77, 0x78, 0x8a, 0xc6, 0xac, 0xa0, 0x7b, 0xd8, 0xb2, 0xcc, 0xb7,
0xf5, 0xc6, 0xd1, 0xfd, 0x2a, 0xc3, 0x73, 0xe4, 0xe6, 0xb4, 0x05, 0xb1, 0x65, 0x99, 0xf4, 0x07,
0xc1, 0x60, 0xe1, 0x92, 0xb1, 0x1e, 0xac, 0x32, 0x89, 0x9f, 0x91, 0xc3, 0x2b, 0xc5, 0x78, 0x29,
0xfd, 0x61, 0x60, 0x2d, 0xbc, 0xe4, 0x36, 0x3a, 0xf7, 0x1e, 0x75, 0xfa, 0x6b, 0x03, 0x22, 0x47,
0x74, 0x78, 0x6f, 0x7c, 0xf5, 0xf3, 0x4e, 0xa4, 0xa9, 0xf3, 0x72, 0xab, 0xda, 0x0a, 0x7c, 0xcb,
0x88, 0x74, 0x83, 0xb7, 0xb6, 0x82, 0xf0, 0x0b, 0x5d, 0x99, 0x0c, 0xb2, 0xe2, 0xa5, 0x04, 0x1c,
0x20, 0x9b, 0x4b, 0x1d, 0xc0, 0x4b, 0x26, 0xbd, 0x9e, 0x49, 0x1f, 0xad, 0x37, 0xc4, 0xe6, 0x12,
0x63, 0x34, 0x04, 0x2e, 0x73, 0x1d, 0x65, 0x4c, 0x74, 0x8d, 0x13, 0xe4, 0x08, 0x90, 0x75, 0xae,
0x4c, 0x0a, 0x2f, 0xf1, 0xff, 0x5b, 0x25, 0x1a, 0x40, 0x8e, 0xc0, 0xf0, 0x1b, 0x8d, 0xcc, 0xe8,
0xe2, 0xe1, 0x96, 0xe8, 0xba, 0xf3, 0x09, 0x82, 0xee, 0x58, 0xce, 0x14, 0x03, 0xe9, 0xdb, 0x9a,
0x7d, 0x7e, 0x6a, 0xec, 0xfd, 0x0f, 0xa8, 0x25, 0xe7, 0xdf, 0x74, 0x86, 0x75, 0xf4, 0x81, 0x26,
0xd7, 0x75, 0xf2, 0x8a, 0x9c, 0x8d, 0xb1, 0x86, 0x97, 0x68, 0xd8, 0x95, 0xf8, 0xc2, 0x75, 0xfb,
0xbf, 0x3b, 0xbb, 0xbb, 0xb4, 0x36, 0x87, 0x7b, 0x71, 0x3f, 0x9c, 0x7e, 0xb5, 0x1b, 0xe9, 0xf7,
0xf1, 0xf8, 0x1b, 0x00, 0x00, 0xff, 0xff, 0xb4, 0xfb, 0xa8, 0xd9, 0x86, 0x02, 0x00, 0x00,
// 377 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x92, 0xc1, 0x6b, 0xdb, 0x30,
0x14, 0xc6, 0xb1, 0x13, 0xe2, 0xf8, 0x79, 0xb0, 0xa0, 0xc3, 0x70, 0x12, 0xb6, 0x19, 0x9f, 0xc2,
0x0e, 0x36, 0xf3, 0x60, 0xbb, 0x0f, 0x72, 0xc8, 0x29, 0x45, 0x29, 0x3d, 0xf4, 0x12, 0x64, 0x59,
0x4d, 0x05, 0x8e, 0xe5, 0x48, 0xb2, 0xa9, 0xe9, 0x7f, 0xd2, 0xbf, 0xb6, 0x58, 0x72, 0xa0, 0x49,
0xc9, 0xed, 0xe9, 0xbd, 0xcf, 0x4f, 0xbf, 0xef, 0xb3, 0x60, 0x2e, 0x6b, 0x9a, 0x2a, 0x4a, 0xaa,
0x8a, 0xc9, 0x54, 0x31, 0xd9, 0x72, 0xca, 0x92, 0x5a, 0x0a, 0x2d, 0xd0, 0x4c, 0x4b, 0xde, 0x76,
0xc9, 0x30, 0x4c, 0xda, 0xdf, 0x8b, 0xbf, 0x07, 0xae, 0x9f, 0x9b, 0x3c, 0xa1, 0xe2, 0x98, 0x92,
0x53, 0x43, 0x14, 0xa3, 0x8d, 0xe4, 0xba, 0x4b, 0x8d, 0x32, 0xed, 0x57, 0x51, 0x71, 0x3c, 0x8a,
0xea, 0x72, 0x53, 0xfc, 0xe6, 0x40, 0xb0, 0xa3, 0xa4, 0xc2, 0xec, 0xd4, 0x30, 0xa5, 0xd1, 0x37,
0x98, 0x68, 0x22, 0x0f, 0x4c, 0x87, 0x4e, 0xe4, 0xac, 0x7c, 0x3c, 0x9c, 0xd0, 0x4f, 0x08, 0x88,
0xd4, 0xfc, 0x89, 0x50, 0xbd, 0xe7, 0x45, 0xe8, 0x9a, 0x21, 0x9c, 0x5b, 0x9b, 0x02, 0xcd, 0x61,
0x9a, 0x97, 0x22, 0xdf, 0xf3, 0x42, 0x85, 0xa3, 0x68, 0xb4, 0xf2, 0xb1, 0xd7, 0x9f, 0x37, 0x85,
0x42, 0xff, 0xc0, 0x13, 0xb5, 0xe6, 0xa2, 0x52, 0xe1, 0x38, 0x72, 0x56, 0x41, 0xf6, 0x3d, 0xb9,
0xe6, 0x4f, 0x7a, 0x86, 0xad, 0x15, 0xe1, 0xb3, 0x3a, 0xfe, 0x65, 0xd9, 0x86, 0x3e, 0x5a, 0x82,
0xdf, 0x36, 0x65, 0xb5, 0xd7, 0x5d, 0xcd, 0x42, 0xc7, 0xdc, 0x31, 0xed, 0x1b, 0xf7, 0x5d, 0xcd,
0xe2, 0x17, 0xf8, 0x62, 0x7d, 0xa8, 0x5a, 0x54, 0x8a, 0xa1, 0x08, 0x5c, 0xa1, 0x8c, 0x89, 0x20,
0x9b, 0x0d, 0xf7, 0xd9, 0x04, 0x92, 0xed, 0x0e, 0xbb, 0x42, 0x21, 0x04, 0x63, 0x26, 0x54, 0x69,
0xbc, 0x4c, 0xb1, 0xa9, 0x51, 0x06, 0x9e, 0x64, 0xaa, 0x29, 0xb5, 0x35, 0x11, 0x64, 0xe1, 0x67,
0x54, 0x6c, 0x04, 0xf8, 0x2c, 0x8c, 0x5f, 0x61, 0x62, 0x5b, 0x37, 0xc3, 0x5b, 0xc3, 0xd7, 0x9e,
0x93, 0x49, 0x92, 0xf3, 0x92, 0x6b, 0xce, 0x54, 0xe8, 0x9a, 0xed, 0xcb, 0x4b, 0xb0, 0x87, 0x0f,
0xa2, 0x0e, 0x5f, 0x7f, 0xd3, 0x03, 0x1b, 0xeb, 0x23, 0xb3, 0xdc, 0xd4, 0xd9, 0x1d, 0x78, 0x3b,
0x8b, 0x86, 0xd6, 0x30, 0xee, 0x4b, 0x74, 0x23, 0xdd, 0xe1, 0x0f, 0x2f, 0x7e, 0xdc, 0x1a, 0xdb,
0xe0, 0xfe, 0xfb, 0x8f, 0xde, 0x30, 0xca, 0x27, 0xe6, 0x8d, 0xfc, 0x79, 0x0f, 0x00, 0x00, 0xff,
0xff, 0xdf, 0x43, 0x89, 0x65, 0x8a, 0x02, 0x00, 0x00,
}

View File

@@ -10,10 +10,10 @@ service Scanner {
}
message ScanRequest {
string target = 1; // image name or tar file path
string image_id = 2;
repeated string layer_ids = 3;
ScanOptions options = 4;
string target = 1; // image name or tar file path
string artifact_id = 2;
repeated string blob_ids = 3;
ScanOptions options = 4;
}
message ScanOptions {

View File

@@ -17,6 +17,7 @@ import fmt "fmt"
import ioutil "io/ioutil"
import http "net/http"
import strconv "strconv"
import gzip "compress/gzip"
import jsonpb "github.com/golang/protobuf/jsonpb"
import proto "github.com/golang/protobuf/proto"
@@ -28,6 +29,9 @@ import io "io"
import json "encoding/json"
import url "net/url"
// A response is compressed with gzip when the response size exceeds this threshold.
const CompressThreshold = 10000
// =================
// Scanner Interface
// =================
@@ -320,6 +324,16 @@ func (s *scannerServer) serveScanProtobuf(ctx context.Context, resp http.Respons
return
}
// Compress the response if the size exceeds the threshold
if len(respBytes) > CompressThreshold && isGZipAcceptable(req) {
respBytes, err = compressWithGzip(respBytes)
if err != nil {
s.writeError(ctx, resp, wrapInternal(err, "failed to compress response"))
return
}
resp.Header().Set("Content-Encoding", "gzip")
}
ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK)
resp.Header().Set("Content-Type", "application/protobuf")
resp.Header().Set("Content-Length", strconv.Itoa(len(respBytes)))
@@ -478,6 +492,7 @@ func newRequest(ctx context.Context, url string, reqBody io.Reader, contentType
}
req.Header.Set("Accept", contentType)
req.Header.Set("Content-Type", contentType)
req.Header.Set("Accept-Encoding", "gzip")
req.Header.Set("Twirp-Version", "v5.10.1")
return req, nil
}
@@ -730,7 +745,15 @@ func doProtobufRequest(ctx context.Context, client HTTPClient, hooks *twirp.Clie
return errorFromResponse(resp)
}
respBodyBytes, err := ioutil.ReadAll(resp.Body)
r := resp.Body
if resp.Header.Get("Content-Encoding") == "gzip" {
r, err = gzip.NewReader(r)
if err != nil {
return wrapInternal(err, "invalid gzip")
}
}
respBodyBytes, err := ioutil.ReadAll(r)
if err != nil {
return wrapInternal(err, "failed to read response body")
}
@@ -835,6 +858,36 @@ func callError(ctx context.Context, h *twirp.ServerHooks, err twirp.Error) conte
return h.Error(ctx, err)
}
// compressWithGzip compresses the data with gzip
func compressWithGzip(data []byte) ([]byte, error) {
var b bytes.Buffer
gz := gzip.NewWriter(&b)
defer gz.Close()
if _, err := gz.Write(data); err != nil {
return nil, err
}
if err := gz.Flush(); err != nil {
return nil, err
}
if err := gz.Close(); err != nil {
return nil, err
}
return b.Bytes(), nil
}
func isGZipAcceptable(request *http.Request) bool {
for _, encoding := range request.Header["Accept-Encoding"] {
if encoding == "gzip" {
return true
}
}
return false
}
func callClientResponseReceived(ctx context.Context, h *twirp.ClientHooks) {
if h == nil || h.ResponseReceived == nil {
return
@@ -857,28 +910,29 @@ func callClientError(ctx context.Context, h *twirp.ClientHooks, err twirp.Error)
}
var twirpFileDescriptor0 = []byte{
// 367 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x52, 0x4d, 0x6b, 0x83, 0x30,
0x18, 0x46, 0x5b, 0x6a, 0x8d, 0x83, 0x95, 0x1c, 0x86, 0x6d, 0xd9, 0x10, 0x4f, 0x65, 0x07, 0x65,
0x0e, 0xb6, 0xfb, 0xa0, 0x87, 0x9e, 0x3a, 0xd2, 0xb1, 0xc3, 0x2e, 0x25, 0xd5, 0x97, 0x2e, 0xa0,
0xc6, 0x26, 0x51, 0x26, 0xfb, 0x1f, 0xfb, 0xbd, 0xc3, 0xc4, 0xc2, 0xda, 0xd1, 0xdb, 0xfb, 0xf1,
0xf8, 0x7c, 0xbc, 0x06, 0x4d, 0x45, 0x95, 0xc6, 0x32, 0xa5, 0x65, 0x09, 0x22, 0x96, 0x20, 0x1a,
0x96, 0x42, 0x54, 0x09, 0xae, 0x38, 0x9e, 0x28, 0xc1, 0x9a, 0x36, 0xea, 0x97, 0x51, 0xf3, 0x30,
0x7b, 0xda, 0x33, 0xf5, 0x59, 0xef, 0xa2, 0x94, 0x17, 0x31, 0x3d, 0xd4, 0x54, 0x42, 0x5a, 0x0b,
0xa6, 0xda, 0x58, 0x23, 0xe3, 0x8e, 0x2a, 0xe5, 0x45, 0xc1, 0xcb, 0x53, 0xa6, 0xf0, 0xc7, 0x42,
0xde, 0x26, 0xa5, 0x25, 0x81, 0x43, 0x0d, 0x52, 0xe1, 0x1b, 0x34, 0x52, 0x54, 0xec, 0x41, 0xf9,
0x56, 0x60, 0x2d, 0x5c, 0xd2, 0x77, 0x78, 0x8a, 0xc6, 0xac, 0xa0, 0x7b, 0xd8, 0xb2, 0xcc, 0xb7,
0xf5, 0xc6, 0xd1, 0xfd, 0x2a, 0xc3, 0x73, 0xe4, 0xe6, 0xb4, 0x05, 0xb1, 0x65, 0x99, 0xf4, 0x07,
0xc1, 0x60, 0xe1, 0x92, 0xb1, 0x1e, 0xac, 0x32, 0x89, 0x9f, 0x91, 0xc3, 0x2b, 0xc5, 0x78, 0x29,
0xfd, 0x61, 0x60, 0x2d, 0xbc, 0xe4, 0x36, 0x3a, 0xf7, 0x1e, 0x75, 0xfa, 0x6b, 0x03, 0x22, 0x47,
0x74, 0x78, 0x6f, 0x7c, 0xf5, 0xf3, 0x4e, 0xa4, 0xa9, 0xf3, 0x72, 0xab, 0xda, 0x0a, 0x7c, 0xcb,
0x88, 0x74, 0x83, 0xb7, 0xb6, 0x82, 0xf0, 0x0b, 0x5d, 0x99, 0x0c, 0xb2, 0xe2, 0xa5, 0x04, 0x1c,
0x20, 0x9b, 0x4b, 0x1d, 0xc0, 0x4b, 0x26, 0xbd, 0x9e, 0x49, 0x1f, 0xad, 0x37, 0xc4, 0xe6, 0x12,
0x63, 0x34, 0x04, 0x2e, 0x73, 0x1d, 0x65, 0x4c, 0x74, 0x8d, 0x13, 0xe4, 0x08, 0x90, 0x75, 0xae,
0x4c, 0x0a, 0x2f, 0xf1, 0xff, 0x5b, 0x25, 0x1a, 0x40, 0x8e, 0xc0, 0xf0, 0x1b, 0x8d, 0xcc, 0xe8,
0xe2, 0xe1, 0x96, 0xe8, 0xba, 0xf3, 0x09, 0x82, 0xee, 0x58, 0xce, 0x14, 0x03, 0xe9, 0xdb, 0x9a,
0x7d, 0x7e, 0x6a, 0xec, 0xfd, 0x0f, 0xa8, 0x25, 0xe7, 0xdf, 0x74, 0x86, 0x75, 0xf4, 0x81, 0x26,
0xd7, 0x75, 0xf2, 0x8a, 0x9c, 0x8d, 0xb1, 0x86, 0x97, 0x68, 0xd8, 0x95, 0xf8, 0xc2, 0x75, 0xfb,
0xbf, 0x3b, 0xbb, 0xbb, 0xb4, 0x36, 0x87, 0x7b, 0x71, 0x3f, 0x9c, 0x7e, 0xb5, 0x1b, 0xe9, 0xf7,
0xf1, 0xf8, 0x1b, 0x00, 0x00, 0xff, 0xff, 0xb4, 0xfb, 0xa8, 0xd9, 0x86, 0x02, 0x00, 0x00,
// 377 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x92, 0xc1, 0x6b, 0xdb, 0x30,
0x14, 0xc6, 0xb1, 0x13, 0xe2, 0xf8, 0x79, 0xb0, 0xa0, 0xc3, 0x70, 0x12, 0xb6, 0x19, 0x9f, 0xc2,
0x0e, 0x36, 0xf3, 0x60, 0xbb, 0x0f, 0x72, 0xc8, 0x29, 0x45, 0x29, 0x3d, 0xf4, 0x12, 0x64, 0x59,
0x4d, 0x05, 0x8e, 0xe5, 0x48, 0xb2, 0xa9, 0xe9, 0x7f, 0xd2, 0xbf, 0xb6, 0x58, 0x72, 0xa0, 0x49,
0xc9, 0xed, 0xe9, 0xbd, 0xcf, 0x4f, 0xbf, 0xef, 0xb3, 0x60, 0x2e, 0x6b, 0x9a, 0x2a, 0x4a, 0xaa,
0x8a, 0xc9, 0x54, 0x31, 0xd9, 0x72, 0xca, 0x92, 0x5a, 0x0a, 0x2d, 0xd0, 0x4c, 0x4b, 0xde, 0x76,
0xc9, 0x30, 0x4c, 0xda, 0xdf, 0x8b, 0xbf, 0x07, 0xae, 0x9f, 0x9b, 0x3c, 0xa1, 0xe2, 0x98, 0x92,
0x53, 0x43, 0x14, 0xa3, 0x8d, 0xe4, 0xba, 0x4b, 0x8d, 0x32, 0xed, 0x57, 0x51, 0x71, 0x3c, 0x8a,
0xea, 0x72, 0x53, 0xfc, 0xe6, 0x40, 0xb0, 0xa3, 0xa4, 0xc2, 0xec, 0xd4, 0x30, 0xa5, 0xd1, 0x37,
0x98, 0x68, 0x22, 0x0f, 0x4c, 0x87, 0x4e, 0xe4, 0xac, 0x7c, 0x3c, 0x9c, 0xd0, 0x4f, 0x08, 0x88,
0xd4, 0xfc, 0x89, 0x50, 0xbd, 0xe7, 0x45, 0xe8, 0x9a, 0x21, 0x9c, 0x5b, 0x9b, 0x02, 0xcd, 0x61,
0x9a, 0x97, 0x22, 0xdf, 0xf3, 0x42, 0x85, 0xa3, 0x68, 0xb4, 0xf2, 0xb1, 0xd7, 0x9f, 0x37, 0x85,
0x42, 0xff, 0xc0, 0x13, 0xb5, 0xe6, 0xa2, 0x52, 0xe1, 0x38, 0x72, 0x56, 0x41, 0xf6, 0x3d, 0xb9,
0xe6, 0x4f, 0x7a, 0x86, 0xad, 0x15, 0xe1, 0xb3, 0x3a, 0xfe, 0x65, 0xd9, 0x86, 0x3e, 0x5a, 0x82,
0xdf, 0x36, 0x65, 0xb5, 0xd7, 0x5d, 0xcd, 0x42, 0xc7, 0xdc, 0x31, 0xed, 0x1b, 0xf7, 0x5d, 0xcd,
0xe2, 0x17, 0xf8, 0x62, 0x7d, 0xa8, 0x5a, 0x54, 0x8a, 0xa1, 0x08, 0x5c, 0xa1, 0x8c, 0x89, 0x20,
0x9b, 0x0d, 0xf7, 0xd9, 0x04, 0x92, 0xed, 0x0e, 0xbb, 0x42, 0x21, 0x04, 0x63, 0x26, 0x54, 0x69,
0xbc, 0x4c, 0xb1, 0xa9, 0x51, 0x06, 0x9e, 0x64, 0xaa, 0x29, 0xb5, 0x35, 0x11, 0x64, 0xe1, 0x67,
0x54, 0x6c, 0x04, 0xf8, 0x2c, 0x8c, 0x5f, 0x61, 0x62, 0x5b, 0x37, 0xc3, 0x5b, 0xc3, 0xd7, 0x9e,
0x93, 0x49, 0x92, 0xf3, 0x92, 0x6b, 0xce, 0x54, 0xe8, 0x9a, 0xed, 0xcb, 0x4b, 0xb0, 0x87, 0x0f,
0xa2, 0x0e, 0x5f, 0x7f, 0xd3, 0x03, 0x1b, 0xeb, 0x23, 0xb3, 0xdc, 0xd4, 0xd9, 0x1d, 0x78, 0x3b,
0x8b, 0x86, 0xd6, 0x30, 0xee, 0x4b, 0x74, 0x23, 0xdd, 0xe1, 0x0f, 0x2f, 0x7e, 0xdc, 0x1a, 0xdb,
0xe0, 0xfe, 0xfb, 0x8f, 0xde, 0x30, 0xca, 0x27, 0xe6, 0x8d, 0xfc, 0x79, 0x0f, 0x00, 0x00, 0xff,
0xff, 0xdf, 0x43, 0x89, 0x65, 0x8a, 0x02, 0x00, 0x00,
}