diff --git a/go.mod b/go.mod index 9096d4468f64..955df782cc59 100644 --- a/go.mod +++ b/go.mod @@ -20,6 +20,7 @@ require ( github.com/kylelemons/godebug v1.1.0 github.com/mattn/go-colorable v0.1.4 // indirect github.com/olekukonko/tablewriter v0.0.2-0.20190607075207-195002e6e56a + github.com/spf13/afero v1.2.2 github.com/stretchr/testify v1.4.0 github.com/twitchtv/twirp v5.10.1+incompatible github.com/urfave/cli v1.22.1 diff --git a/go.sum b/go.sum index ae71c93487cf..4ec67ca96fb9 100644 --- a/go.sum +++ b/go.sum @@ -34,7 +34,6 @@ github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 h1:ygIc8M6tr github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= -github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= @@ -68,7 +67,6 @@ github.com/aws/aws-sdk-go v1.19.11/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpi 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= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= @@ -84,7 +82,6 @@ github.com/cheggaaa/pb/v3 v3.0.3/go.mod h1:Pp35CDuiEpHa/ZLGCtBbM6CBwMstv1bJlG884 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/containerd/containerd v1.3.0 h1:xjvXQWABwS2uiv3TWgQt5Uth60Gu86LTGZXMJkjc7rY= github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.3.3 h1:LoIzb5y9x5l8VKAlyrbusNPXqBY0+kviRloxFUMFwKc= github.com/containerd/containerd v1.3.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= @@ -113,7 +110,6 @@ github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9r github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= -github.com/docker/cli v0.0.0-20180920165730-54c19e67f69c h1:QlAVcyoF7QQVN7zV+xYBjgwtRVlRU3WCTCpb2mcqQrM= github.com/docker/cli v0.0.0-20180920165730-54c19e67f69c/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017 h1:2HQmlpI3yI9deH18Q6xiSOIjXD4sLI55Y/gfpa8/558= github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= @@ -121,7 +117,6 @@ github.com/docker/distribution v0.0.0-20180920194744-16128bbac47f/go.mod h1:J2gT github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v0.0.0-20180924202107-a9c061deec0f h1:W4fbqg0JUwy6lLesoJaV/rE0fwAmtdtinMa64X1CEh0= github.com/docker/docker v0.0.0-20180924202107-a9c061deec0f/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v0.7.3-0.20190506211059-b20a14b54661/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= @@ -172,7 +167,6 @@ github.com/genuinetools/pkg v0.0.0-20180910213200-1c141f661797/go.mod h1:XTcrCYl github.com/genuinetools/reg v0.16.0 h1:ZhLZPT+aUGHLfy45Ub5FLWik+3Dij1iwaj8A/GyAZBw= github.com/genuinetools/reg v0.16.0/go.mod h1:12Fe9EIvK3dG/qWhNk5e9O96I8SGmCKLsJ8GsXUbk+Y= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= 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= @@ -200,11 +194,9 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= @@ -221,7 +213,6 @@ github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8l github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -249,7 +240,6 @@ github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGa github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= @@ -263,7 +253,6 @@ github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= @@ -333,7 +322,6 @@ github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.6 h1:V2iyH+aX9C5fsYCpK60U8BYIvmhqxuOL3JZcqc1NB7k= github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -383,7 +371,6 @@ github.com/peterhellberg/link v1.0.0 h1:mUWkiegowUXEcmlb+ybF75Q/8D2Y0BjZtR8cxoKh github.com/peterhellberg/link v1.0.0/go.mod h1:gtSlOT4jmkY8P47hbTc8PTgiDDWpdPbFYl75keYyBB8= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -397,7 +384,6 @@ github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= @@ -427,7 +413,6 @@ github.com/simplereach/timeutils v1.2.0/go.mod h1:VVbQDfN/FHRZa1LSqcwo4kNZ62OOyq github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.5.0 h1:1N5EYkVAPEywqZRJd7cwnRtCb6xJx7NH3T3WUTF980Q= github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo= @@ -437,6 +422,7 @@ github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2 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/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= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= @@ -449,7 +435,6 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= @@ -545,7 +530,6 @@ golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20191108221443-4ba9e2ef068c h1:SRpq/kuj/xNci/RdvEs+RSvpfxqvLAzTKuKGlzoGdZQ= golang.org/x/net v0.0.0-20191108221443-4ba9e2ef068c/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 h1:Wo7BWFiOk0QRFMLYMqJGFMd9CgUAcGx7V+qEg/h5IBI= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -581,7 +565,6 @@ golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9 h1:ZBzSG/7F4eNKz2L3GE9o300RX0Az1Bw5HF7PDraD+qU= golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775 h1:TC0v2RSO1u2kn1ZugjrFXkRZAEaqMN/RW+OTZkBzmLE= golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -592,7 +575,6 @@ golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -622,7 +604,6 @@ golang.org/x/tools v0.0.0-20200210192313-1ace956b0e17 h1:a/Fd23DJvg1CaeDH0dYHahE golang.org/x/tools v0.0.0-20200210192313-1ace956b0e17/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -633,7 +614,6 @@ google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMt google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.6.1-0.20190607001116-5213b8090861/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -642,7 +622,6 @@ google.golang.org/genproto v0.0.0-20180924164928-221a8d4f7494/go.mod h1:JiN7NxoA google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873 h1:nfPFGzJkUDX6uBmpN/pSw7MbOAWegH5QDQuoXFHedLg= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= @@ -652,7 +631,6 @@ google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.24.0 h1:vb/1TCsVn3DcJlQ0Gs1yB1pKI6Do2/QNwxdKqmc/b0s= google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.28.0 h1:bO/TA4OxCOummhSf10siHuG7vJOiwh7SpRpFZDkOgl4= @@ -688,7 +666,6 @@ gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRN gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -718,7 +695,6 @@ k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= k8s.io/legacy-cloud-providers v0.17.4/go.mod h1:FikRNoD64ECjkxO36gkDgJeiQWwyZTuBkhu+yxOc1Js= -k8s.io/utils v0.0.0-20191010214722-8d271d903fe4 h1:Gi+/O1saihwDqnlmC8Vhv1M5Sp4+rbOmK9TbsLn8ZEA= k8s.io/utils v0.0.0-20191010214722-8d271d903fe4/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20191114184206-e782cd3c129f h1:GiPwtSzdP43eI1hpPCbROQCCIgCuiMMNF8YUVLF3vJo= k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= diff --git a/integration/client_server_test.go b/integration/client_server_test.go index de793596c738..41f03ac126a3 100644 --- a/integration/client_server_test.go +++ b/integration/client_server_test.go @@ -330,7 +330,8 @@ func TestClientServer(t *testing.T) { for _, c := range cases { t.Run(c.name, func(t *testing.T) { // Copy DB file - cacheDir := gunzipDB() + cacheDir, err := gunzipDB() + require.NoError(t, err) defer os.RemoveAll(cacheDir) port, err := getFreePort() diff --git a/integration/docker_engine_test.go b/integration/docker_engine_test.go index 1ca0185e1e9e..db70156a6dd6 100644 --- a/integration/docker_engine_test.go +++ b/integration/docker_engine_test.go @@ -237,7 +237,8 @@ func TestRun_WithDockerEngine(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { // Copy DB file - cacheDir := gunzipDB() + cacheDir, err := gunzipDB() + require.NoError(t, err) defer os.RemoveAll(cacheDir) ctx := context.Background() diff --git a/integration/integration_test.go b/integration/integration_test.go index 84c55f544ded..fdc14163ddcb 100644 --- a/integration/integration_test.go +++ b/integration/integration_test.go @@ -8,46 +8,62 @@ import ( "flag" "io" "io/ioutil" - "log" "net" "os" "path/filepath" "time" + + dbFile "github.com/aquasecurity/trivy/pkg/db" + + "github.com/aquasecurity/trivy-db/pkg/db" + "github.com/spf13/afero" ) var update = flag.Bool("update", false, "update golden files") -func gunzipDB() string { +func gunzipDB() (string, error) { gz, err := os.Open("testdata/trivy.db.gz") if err != nil { - log.Panic(err) + return "", err } zr, err := gzip.NewReader(gz) if err != nil { - log.Panic(err) + return "", err } tmpDir, err := ioutil.TempDir("", "integration") if err != nil { - log.Panic(err) + return "", err } - dbDir := filepath.Join(tmpDir, "db") + + dbPath := db.Path(tmpDir) + dbDir := filepath.Dir(dbPath) err = os.MkdirAll(dbDir, 0700) if err != nil { - log.Panic(err) + return "", err } - file, err := os.Create(filepath.Join(dbDir, "trivy.db")) + file, err := os.Create(dbPath) if err != nil { - log.Panic(err) + return "", err } defer file.Close() - _, err = io.Copy(file, zr) + if _, err = io.Copy(file, zr); err != nil { + return "", err + } + + err = dbFile.NewMetadata(afero.NewOsFs(), tmpDir).Store(db.Metadata{ + Version: 1, + Type: 1, + NextUpdate: time.Time{}, + UpdatedAt: time.Time{}, + }) if err != nil { - log.Panic(err) + return "", err } - return tmpDir + + return tmpDir, nil } func getFreePort() (int, error) { diff --git a/integration/standalone_test.go b/integration/standalone_test.go index fe807932bd63..a4d18d21281a 100644 --- a/integration/standalone_test.go +++ b/integration/standalone_test.go @@ -8,6 +8,8 @@ import ( "strings" "testing" + "github.com/stretchr/testify/require" + "github.com/aquasecurity/trivy/internal" "github.com/stretchr/testify/assert" @@ -346,7 +348,8 @@ func TestRun_WithTar(t *testing.T) { for _, c := range cases { t.Run(c.name, func(t *testing.T) { // Copy DB file - cacheDir := gunzipDB() + cacheDir, err := gunzipDB() + require.NoError(t, err) defer os.RemoveAll(cacheDir) // Setup CLI App diff --git a/internal/app.go b/internal/app.go index 3ef05ffb6b48..dcc27aa7eba8 100644 --- a/internal/app.go +++ b/internal/app.go @@ -7,14 +7,15 @@ import ( "strings" "time" - "github.com/aquasecurity/trivy-db/pkg/db" - + "github.com/spf13/afero" "github.com/urfave/cli" + "github.com/aquasecurity/trivy-db/pkg/db" "github.com/aquasecurity/trivy-db/pkg/types" "github.com/aquasecurity/trivy/internal/client" "github.com/aquasecurity/trivy/internal/server" "github.com/aquasecurity/trivy/internal/standalone" + tdb "github.com/aquasecurity/trivy/pkg/db" "github.com/aquasecurity/trivy/pkg/utils" "github.com/aquasecurity/trivy/pkg/vulnerability" ) @@ -249,16 +250,13 @@ OPTIONS: func showVersion(cacheDir, outputFormat, version string, outputWriter io.Writer) { var dbMeta *db.Metadata - err := db.Init(cacheDir) - if err == nil { - metadata, _ := db.Config{}.GetMetadata() - if !metadata.UpdatedAt.IsZero() && !metadata.NextUpdate.IsZero() && metadata.Version != 0 { - dbMeta = &db.Metadata{ - Version: metadata.Version, - Type: metadata.Type, - NextUpdate: metadata.NextUpdate.UTC(), - UpdatedAt: metadata.UpdatedAt.UTC(), - } + metadata, _ := tdb.NewMetadata(afero.NewOsFs(), cacheDir).Get() + if !metadata.UpdatedAt.IsZero() && !metadata.NextUpdate.IsZero() && metadata.Version != 0 { + dbMeta = &db.Metadata{ + Version: metadata.Version, + Type: metadata.Type, + NextUpdate: metadata.NextUpdate.UTC(), + UpdatedAt: metadata.UpdatedAt.UTC(), } } diff --git a/internal/app_test.go b/internal/app_test.go index 671d02421a7d..e61236eeb5ac 100644 --- a/internal/app_test.go +++ b/internal/app_test.go @@ -1,25 +1,23 @@ package internal import ( + "bytes" "io/ioutil" "os" + "path/filepath" "testing" "time" + "github.com/stretchr/testify/require" + + dbFile "github.com/aquasecurity/trivy/pkg/db" + "github.com/spf13/afero" + "github.com/aquasecurity/trivy-db/pkg/db" "github.com/stretchr/testify/assert" ) -type fakeIOWriter struct { - written []byte -} - -func (f *fakeIOWriter) Write(p []byte) (n int, err error) { - f.written = append(f.written, p...) - return len(p), nil -} - func Test_showVersion(t *testing.T) { type args struct { cacheDir string @@ -85,27 +83,26 @@ Vulnerability DB: cacheDir = tt.args.cacheDir default: cacheDir, _ = ioutil.TempDir("", "Test_showVersion-*") - defer func() { - os.RemoveAll(cacheDir) - }() + defer os.RemoveAll(cacheDir) } if tt.createDB { - db.Init(cacheDir) - db.Config{}.SetMetadata(db.Metadata{ + m := dbFile.NewMetadata(afero.NewOsFs(), cacheDir) + err := os.MkdirAll(filepath.Join(cacheDir, "db"), os.ModePerm) + require.NoError(t, err) + + err = m.Store(db.Metadata{ Version: 42, Type: 1, NextUpdate: time.Unix(1584403020, 0), UpdatedAt: time.Unix(1584402020, 0), }) - db.Close() + require.NoError(t, err) } - var wb []byte - fw := fakeIOWriter{written: wb} - - showVersion(cacheDir, tt.args.outputFormat, tt.args.version, &fw) - assert.Equal(t, tt.expectedOutput, string(fw.written), tt.name) + fw := new(bytes.Buffer) + showVersion(cacheDir, tt.args.outputFormat, tt.args.version, fw) + assert.Equal(t, tt.expectedOutput, fw.String(), tt.name) }) } } diff --git a/internal/operation/inject.go b/internal/operation/inject.go index fc6aebd12672..ac77ef1fc96e 100644 --- a/internal/operation/inject.go +++ b/internal/operation/inject.go @@ -7,7 +7,7 @@ import ( "github.com/google/wire" ) -func initializeDBClient(quiet bool) db.Client { +func initializeDBClient(cacheDir string, quiet bool) db.Client { wire.Build(db.SuperSet) return db.Client{} } diff --git a/internal/operation/operation.go b/internal/operation/operation.go index cb4a8088b3b3..6adab17dbe53 100644 --- a/internal/operation/operation.go +++ b/internal/operation/operation.go @@ -4,11 +4,13 @@ import ( "context" "os" + "github.com/spf13/afero" + "github.com/google/wire" "golang.org/x/xerrors" "github.com/aquasecurity/fanal/cache" - "github.com/aquasecurity/trivy-db/pkg/db" + "github.com/aquasecurity/trivy/pkg/db" "github.com/aquasecurity/trivy/pkg/log" "github.com/aquasecurity/trivy/pkg/utils" ) @@ -29,10 +31,10 @@ func NewCache(client cache.LocalImageCache) Cache { func (c Cache) Reset() (err error) { if err := c.ClearDB(); err != nil { - return err + return xerrors.Errorf("failed to clear the database: %w", err) } if err := c.ClearImages(); err != nil { - return err + return xerrors.Errorf("failed to clear the image cache: %w", err) } return nil } @@ -40,7 +42,7 @@ func (c Cache) Reset() (err error) { func (c Cache) ClearDB() (err error) { log.Logger.Info("Removing DB file...") if err = os.RemoveAll(utils.CacheDir()); err != nil { - return xerrors.New("failed to remove cache") + return xerrors.Errorf("failed to remove the directory (%s) : %w", utils.CacheDir(), err) } return nil } @@ -48,44 +50,40 @@ func (c Cache) ClearDB() (err error) { func (c Cache) ClearImages() error { log.Logger.Info("Removing image caches...") if err := c.client.Clear(); err != nil { - return xerrors.New("failed to remove image layer cache") + return xerrors.Errorf("failed to remove the cache: %w", err) } return nil } func DownloadDB(appVersion, cacheDir string, quiet, light, skipUpdate bool) error { - client := initializeDBClient(quiet) + client := initializeDBClient(cacheDir, quiet) ctx := context.Background() - needsUpdate, err := client.NeedsUpdate(ctx, appVersion, light, skipUpdate) + needsUpdate, err := client.NeedsUpdate(appVersion, light, skipUpdate) if err != nil { return xerrors.Errorf("database error: %w", err) } if needsUpdate { log.Logger.Info("Need to update DB") - if err = db.Close(); err != nil { - return xerrors.Errorf("failed db close: %w", err) - } log.Logger.Info("Downloading DB...") if err := client.Download(ctx, cacheDir, light); err != nil { return xerrors.Errorf("failed to download vulnerability DB: %w", err) } - - log.Logger.Info("Reopening DB...") - if err = db.Init(cacheDir); err != nil { - return xerrors.Errorf("failed db close: %w", err) + if err = client.UpdateMetadata(cacheDir); err != nil { + return xerrors.Errorf("unable to update database metadata: %w", err) } } // for debug - if err := showDBInfo(); err != nil { - return xerrors.Errorf("failed to show database info") + if err := showDBInfo(cacheDir); err != nil { + return xerrors.Errorf("failed to show database info: %w", err) } return nil } -func showDBInfo() error { - metadata, err := db.Config{}.GetMetadata() +func showDBInfo(cacheDir string) error { + m := db.NewMetadata(afero.NewOsFs(), cacheDir) + metadata, err := m.Get() if err != nil { return xerrors.Errorf("something wrong with DB: %w", err) } diff --git a/internal/operation/wire_gen.go b/internal/operation/wire_gen.go index 460ec57e2954..1cb76c71f7ae 100644 --- a/internal/operation/wire_gen.go +++ b/internal/operation/wire_gen.go @@ -10,16 +10,19 @@ import ( "github.com/aquasecurity/trivy/pkg/db" "github.com/aquasecurity/trivy/pkg/github" "github.com/aquasecurity/trivy/pkg/indicator" + "github.com/spf13/afero" "k8s.io/utils/clock" ) // Injectors from inject.go: -func initializeDBClient(quiet bool) db.Client { +func initializeDBClient(cacheDir string, quiet bool) db.Client { config := db2.Config{} client := github.NewClient() progressBar := indicator.NewProgressBar(quiet) realClock := clock.RealClock{} - dbClient := db.NewClient(config, client, progressBar, realClock) + fs := afero.NewOsFs() + metadata := db.NewMetadata(fs, cacheDir) + dbClient := db.NewClient(config, client, progressBar, realClock, metadata) return dbClient } diff --git a/internal/server/run.go b/internal/server/run.go index a4b8072afb63..c9bffd4be27b 100644 --- a/internal/server/run.go +++ b/internal/server/run.go @@ -1,10 +1,10 @@ package server import ( - "github.com/aquasecurity/fanal/cache" "github.com/urfave/cli" "golang.org/x/xerrors" + "github.com/aquasecurity/fanal/cache" "github.com/aquasecurity/trivy-db/pkg/db" "github.com/aquasecurity/trivy/internal/operation" "github.com/aquasecurity/trivy/internal/server/config" @@ -42,10 +42,6 @@ func run(c config.Config) (err error) { return cacheOperation.ClearDB() } - if err = db.Init(c.CacheDir); err != nil { - return xerrors.Errorf("error in vulnerability DB initialize: %w", err) - } - // download the database file if err = operation.DownloadDB(c.AppVersion, c.CacheDir, true, false, c.SkipUpdate); err != nil { return err @@ -55,5 +51,9 @@ func run(c config.Config) (err error) { return nil } + if err = db.Init(c.CacheDir); err != nil { + return xerrors.Errorf("error in vulnerability DB initialize: %w", err) + } + return server.ListenAndServe(c, fsCache) } diff --git a/internal/standalone/run.go b/internal/standalone/run.go index 9b3b9b3418ef..39b52374ef65 100644 --- a/internal/standalone/run.go +++ b/internal/standalone/run.go @@ -7,8 +7,9 @@ import ( "os" "strings" - "github.com/aquasecurity/fanal/cache" "github.com/aquasecurity/trivy-db/pkg/db" + + "github.com/aquasecurity/fanal/cache" "github.com/aquasecurity/trivy/internal/operation" "github.com/aquasecurity/trivy/internal/standalone/config" "github.com/aquasecurity/trivy/pkg/log" @@ -55,10 +56,6 @@ func run(c config.Config) (err error) { return cacheOperation.ClearImages() } - if err = db.Init(c.CacheDir); err != nil { - return xerrors.Errorf("error in vulnerability DB initialize: %w", err) - } - // download the database file noProgress := c.Quiet || c.NoProgress if err = operation.DownloadDB(c.AppVersion, c.CacheDir, noProgress, c.Light, c.SkipUpdate); err != nil { @@ -69,6 +66,10 @@ func run(c config.Config) (err error) { return nil } + if err = db.Init(c.CacheDir); err != nil { + return xerrors.Errorf("error in vulnerability DB initialize: %w", err) + } + var scanner scanner.Scanner ctx := context.Background() diff --git a/pkg/db/db.go b/pkg/db/db.go index 4f03542d18a0..09ff8892cb9c 100644 --- a/pkg/db/db.go +++ b/pkg/db/db.go @@ -3,11 +3,13 @@ package db import ( "compress/gzip" "context" + "encoding/json" "io" "os" "path/filepath" "github.com/google/wire" + "github.com/spf13/afero" "golang.org/x/xerrors" "k8s.io/utils/clock" @@ -20,6 +22,8 @@ import ( const ( fullDB = "trivy.db.gz" lightDB = "trivy-light.db.gz" + + metadataFile = "metadata.json" ) var SuperSet = wire.NewSet( @@ -32,23 +36,29 @@ var SuperSet = wire.NewSet( // db.Config wire.Struct(new(db.Config)), + wire.Bind(new(dbOperation), new(db.Config)), // github.Client github.NewClient, wire.Bind(new(github.Operation), new(github.Client)), + // Metadata + afero.NewOsFs, + NewMetadata, + // db.Client NewClient, wire.Bind(new(Operation), new(Client)), ) type Operation interface { - NeedsUpdate(ctx context.Context, cliVersion string, light, skip bool) (bool, error) - Download(ctx context.Context, cacheDir string, light bool) error + NeedsUpdate(cliVersion string, skip, light bool) (need bool, err error) + Download(ctx context.Context, cacheDir string, light bool) (err error) + UpdateMetadata(cacheDir string) (err error) } type dbOperation interface { - GetMetadata() (db.Metadata, error) + GetMetadata() (metadata db.Metadata, err error) } type Client struct { @@ -56,26 +66,28 @@ type Client struct { githubClient github.Operation pb indicator.ProgressBar clock clock.Clock + metadata Metadata } -func NewClient(dbc db.Config, githubClient github.Operation, pb indicator.ProgressBar, clock clock.Clock) Client { +func NewClient(dbc dbOperation, githubClient github.Operation, pb indicator.ProgressBar, clock clock.Clock, metadata Metadata) Client { return Client{ dbc: dbc, githubClient: githubClient, pb: pb, clock: clock, + metadata: metadata, } } -func (c Client) NeedsUpdate(ctx context.Context, cliVersion string, light, skip bool) (bool, error) { +func (c Client) NeedsUpdate(cliVersion string, light, skip bool) (bool, error) { dbType := db.TypeFull if light { dbType = db.TypeLight } - metadata, err := c.dbc.GetMetadata() + metadata, err := c.metadata.Get() if err != nil { - log.Logger.Debug("This is the first run") + log.Logger.Debugf("There is no valid metadata file: %s", err) if skip { log.Logger.Error("The first run cannot skip downloading DB") return false, xerrors.New("--skip-update cannot be specified on the first run") @@ -113,6 +125,11 @@ func (c Client) NeedsUpdate(ctx context.Context, cliVersion string, light, skip } func (c Client) Download(ctx context.Context, cacheDir string, light bool) error { + // Remove the metadata file before downloading DB + if err := c.metadata.Delete(); err != nil { + log.Logger.Debug("no metadata file") + } + dbFile := fullDB if light { dbFile = lightDB @@ -135,6 +152,7 @@ func (c Client) Download(ctx context.Context, cacheDir string, light bool) error dbPath := db.Path(cacheDir) dbDir := filepath.Dir(dbPath) + if err = os.MkdirAll(dbDir, 0700); err != nil { return xerrors.Errorf("failed to mkdir: %w", err) } @@ -145,9 +163,85 @@ func (c Client) Download(ctx context.Context, cacheDir string, light bool) error } defer file.Close() - _, err = io.Copy(file, gr) - if err != nil { + if _, err = io.Copy(file, gr); err != nil { return xerrors.Errorf("failed to save DB file: %w", err) } + + return nil +} + +func (c Client) UpdateMetadata(cacheDir string) error { + log.Logger.Debug("Updating database metadata...") + + // make sure the DB has been successfully downloaded + if err := db.Init(cacheDir); err != nil { + return xerrors.Errorf("DB error: %w", err) + } + defer db.Close() + + metadata, err := c.dbc.GetMetadata() + if err != nil { + return xerrors.Errorf("unable to get a metadata: %w", err) + } + + if err = c.metadata.Store(metadata); err != nil { + return xerrors.Errorf("failed to store metadata: %w", err) + } + + return nil +} + +type Metadata struct { + fs afero.Fs + filePath string +} + +func NewMetadata(fs afero.Fs, cacheDir string) Metadata { + filePath := MetadataPath(cacheDir) + return Metadata{ + fs: fs, + filePath: filePath, + } +} + +func MetadataPath(cacheDir string) string { + dbPath := db.Path(cacheDir) + dbDir := filepath.Dir(dbPath) + return filepath.Join(dbDir, metadataFile) +} + +// StoreMetadata stores database metadata as a file +func (m Metadata) Store(metadata db.Metadata) error { + f, err := m.fs.Create(m.filePath) + if err != nil { + return xerrors.Errorf("unable to create a metadata file: %w", err) + } + defer f.Close() + + if err = json.NewEncoder(f).Encode(metadata); err != nil { + return xerrors.Errorf("unable to encode metadata: %w", err) + } + return nil +} + +// DeleteMetadata deletes the file of database metadata +func (m Metadata) Delete() error { + if err := m.fs.Remove(m.filePath); err != nil { + return xerrors.Errorf("unable to remove the metadata file: %w", err) + } return nil } + +func (m Metadata) Get() (db.Metadata, error) { + f, err := m.fs.Open(m.filePath) + if err != nil { + return db.Metadata{}, xerrors.Errorf("unable to open a file: %w", err) + } + defer f.Close() + + var metadata db.Metadata + if err = json.NewDecoder(f).Decode(&metadata); err != nil { + return db.Metadata{}, xerrors.Errorf("unable to decode metadata: %w", err) + } + return metadata, nil +} diff --git a/pkg/db/db_mock.go b/pkg/db/db_mock.go deleted file mode 100644 index 3700bd2cb82c..000000000000 --- a/pkg/db/db_mock.go +++ /dev/null @@ -1,22 +0,0 @@ -package db - -import ( - "context" - - "github.com/stretchr/testify/mock" -) - -type MockClient struct { - mock.Mock -} - -func (_m *MockClient) NeedsUpdate(a context.Context, b string, c, d bool) (bool, error) { - ret := _m.Called(a, b, c, d) - return ret.Bool(0), ret.Error(1) -} - -func (_m *MockClient) Download(a context.Context, b string, c bool) error { - ret := _m.Called(a, b, c) - return ret.Error(0) - -} diff --git a/pkg/db/db_test.go b/pkg/db/db_test.go index bcc2ba485933..29345ac552b4 100644 --- a/pkg/db/db_test.go +++ b/pkg/db/db_test.go @@ -2,14 +2,16 @@ package db import ( "context" - "errors" "io/ioutil" "os" "testing" "time" + "github.com/aquasecurity/trivy/pkg/github" "github.com/aquasecurity/trivy/pkg/indicator" + "github.com/spf13/afero" + "github.com/stretchr/testify/require" "golang.org/x/xerrors" @@ -18,44 +20,20 @@ import ( clocktesting "k8s.io/utils/clock/testing" "github.com/aquasecurity/trivy-db/pkg/db" - "github.com/aquasecurity/trivy/pkg/github" "github.com/aquasecurity/trivy/pkg/log" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" ) -type MockConfig struct { - mock.Mock -} - -func (_m *MockConfig) GetMetadata() (db.Metadata, error) { - ret := _m.Called() - ret0 := ret.Get(0) - if ret0 == nil { - return db.Metadata{}, ret.Error(1) - } - metadata, ok := ret0.(db.Metadata) - if !ok { - return db.Metadata{}, ret.Error(1) - } - return metadata, ret.Error(1) -} - func TestClient_NeedsUpdate(t *testing.T) { timeNextUpdateDay1 := time.Date(2019, 9, 1, 0, 0, 0, 0, time.UTC) timeNextUpdateDay2 := time.Date(2019, 10, 2, 0, 0, 0, 0, time.UTC) - type getMetadataOutput struct { - metadata db.Metadata - err error - } - testCases := []struct { name string light bool skip bool clock clock.Clock - getMetadata getMetadataOutput + metadata db.Metadata expected bool expectedError error }{ @@ -63,35 +41,28 @@ func TestClient_NeedsUpdate(t *testing.T) { name: "happy path", light: false, clock: clocktesting.NewFakeClock(time.Date(2019, 10, 1, 0, 0, 0, 0, time.UTC)), - getMetadata: getMetadataOutput{ - metadata: db.Metadata{ - Version: 1, - Type: db.TypeFull, - NextUpdate: timeNextUpdateDay1, - }, + metadata: db.Metadata{ + Version: 1, + Type: db.TypeFull, + NextUpdate: timeNextUpdateDay1, }, expected: true, }, { - name: "happy path for first run", - light: false, - clock: clocktesting.NewFakeClock(time.Date(2019, 10, 1, 0, 0, 0, 0, time.UTC)), - getMetadata: getMetadataOutput{ - metadata: db.Metadata{}, - err: errors.New("get metadata failed"), - }, + name: "happy path for first run", + light: false, + clock: clocktesting.NewFakeClock(time.Date(2019, 10, 1, 0, 0, 0, 0, time.UTC)), + metadata: db.Metadata{}, expected: true, }, { name: "happy path with different type", light: true, clock: clocktesting.NewFakeClock(time.Date(2019, 10, 1, 0, 0, 0, 0, time.UTC)), - getMetadata: getMetadataOutput{ - metadata: db.Metadata{ - Version: 1, - Type: db.TypeFull, - NextUpdate: timeNextUpdateDay1, - }, + metadata: db.Metadata{ + Version: 1, + Type: db.TypeFull, + NextUpdate: timeNextUpdateDay1, }, expected: true, }, @@ -99,12 +70,10 @@ func TestClient_NeedsUpdate(t *testing.T) { name: "happy path with old schema version", light: true, clock: clocktesting.NewFakeClock(time.Date(2019, 10, 1, 0, 0, 0, 0, time.UTC)), - getMetadata: getMetadataOutput{ - metadata: db.Metadata{ - Version: 0, - Type: db.TypeFull, - NextUpdate: timeNextUpdateDay1, - }, + metadata: db.Metadata{ + Version: 0, + Type: db.TypeFull, + NextUpdate: timeNextUpdateDay1, }, expected: true, }, @@ -112,12 +81,10 @@ func TestClient_NeedsUpdate(t *testing.T) { name: "happy path with --skip-update", light: false, clock: clocktesting.NewFakeClock(time.Date(2019, 10, 1, 0, 0, 0, 0, time.UTC)), - getMetadata: getMetadataOutput{ - metadata: db.Metadata{ - Version: 1, - Type: db.TypeFull, - NextUpdate: timeNextUpdateDay1, - }, + metadata: db.Metadata{ + Version: 1, + Type: db.TypeFull, + NextUpdate: timeNextUpdateDay1, }, skip: true, expected: false, @@ -126,12 +93,10 @@ func TestClient_NeedsUpdate(t *testing.T) { name: "skip downloading DB", light: false, clock: clocktesting.NewFakeClock(time.Date(2019, 10, 1, 0, 0, 0, 0, time.UTC)), - getMetadata: getMetadataOutput{ - metadata: db.Metadata{ - Version: 1, - Type: db.TypeFull, - NextUpdate: timeNextUpdateDay2, - }, + metadata: db.Metadata{ + Version: 1, + Type: db.TypeFull, + NextUpdate: timeNextUpdateDay2, }, expected: false, }, @@ -139,22 +104,18 @@ func TestClient_NeedsUpdate(t *testing.T) { name: "newer schema version", light: false, clock: clocktesting.NewFakeClock(time.Date(2019, 10, 1, 0, 0, 0, 0, time.UTC)), - getMetadata: getMetadataOutput{ - metadata: db.Metadata{ - Version: 2, - Type: db.TypeFull, - NextUpdate: timeNextUpdateDay2, - }, + metadata: db.Metadata{ + Version: 2, + Type: db.TypeFull, + NextUpdate: timeNextUpdateDay2, }, expectedError: xerrors.New("the version of DB schema doesn't match. Local DB: 2, Expected: 1"), }, { - name: "--skip-update on the first run", - light: false, - clock: clocktesting.NewFakeClock(time.Date(2019, 10, 1, 0, 0, 0, 0, time.UTC)), - getMetadata: getMetadataOutput{ - err: xerrors.New("this is the first run"), - }, + name: "--skip-update on the first run", + light: false, + clock: clocktesting.NewFakeClock(time.Date(2019, 10, 1, 0, 0, 0, 0, time.UTC)), + metadata: db.Metadata{}, skip: true, expectedError: xerrors.New("--skip-update cannot be specified on the first run"), }, @@ -162,12 +123,10 @@ func TestClient_NeedsUpdate(t *testing.T) { name: "--skip-update with different schema version", light: false, clock: clocktesting.NewFakeClock(time.Date(2019, 10, 1, 0, 0, 0, 0, time.UTC)), - getMetadata: getMetadataOutput{ - metadata: db.Metadata{ - Version: 0, - Type: db.TypeFull, - NextUpdate: timeNextUpdateDay1, - }, + metadata: db.Metadata{ + Version: 0, + Type: db.TypeFull, + NextUpdate: timeNextUpdateDay1, }, skip: true, expectedError: xerrors.New("--skip-update cannot be specified with the old DB"), @@ -180,23 +139,19 @@ func TestClient_NeedsUpdate(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - mockConfig := new(MockConfig) - mockConfig.On("GetMetadata").Return( - tc.getMetadata.metadata, tc.getMetadata.err) - - dir, err := ioutil.TempDir("", "db") - require.NoError(t, err, tc.name) - defer os.RemoveAll(dir) - - err = db.Init(dir) - require.NoError(t, err, tc.name) + fs := afero.NewMemMapFs() + metadata := NewMetadata(fs, "/cache") + if tc.metadata != (db.Metadata{}) { + metadata.Store(tc.metadata) + } client := Client{ - dbc: mockConfig, - clock: tc.clock, + //dbc: mockConfig, + clock: tc.clock, + metadata: metadata, } - needsUpdate, err := client.NeedsUpdate(context.Background(), "test", tc.light, tc.skip) + needsUpdate, err := client.NeedsUpdate("test", tc.light, tc.skip) switch { case tc.expectedError != nil: @@ -206,16 +161,22 @@ func TestClient_NeedsUpdate(t *testing.T) { } assert.Equal(t, tc.expected, needsUpdate) - mockConfig.AssertExpectations(t) + //mockConfig.AssertExpectations(t) }) } } func TestClient_Download(t *testing.T) { + type getMetadataOutput struct { + metadata db.Metadata + err error + } + testCases := []struct { name string light bool downloadDB []github.DownloadDBExpectation + getMetadata dbOperationGetMetadataExpectation expectedContent []byte expectedError error }{ @@ -230,6 +191,15 @@ func TestClient_Download(t *testing.T) { }, }, }, + getMetadata: dbOperationGetMetadataExpectation{ + Returns: dbOperationGetMetadataReturns{ + Metadata: db.Metadata{ + Version: 1, + Type: db.TypeFull, + NextUpdate: time.Date(2019, 9, 1, 0, 0, 0, 0, time.UTC), + }, + }, + }, }, { name: "DownloadDB returns an error", @@ -264,18 +234,21 @@ func TestClient_Download(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { + mockConfig := new(mockDbOperation) + mockConfig.ApplyGetMetadataExpectation(tc.getMetadata) + mockGitHubClient, err := github.NewMockClient(tc.downloadDB) require.NoError(t, err, tc.name) + fs := afero.NewMemMapFs() + metadata := NewMetadata(fs, "/cache") + dir, err := ioutil.TempDir("", "db") require.NoError(t, err, tc.name) defer os.RemoveAll(dir) - err = db.Init(dir) - require.NoError(t, err, tc.name) - pb := indicator.NewProgressBar(true) - client := NewClient(db.Config{}, mockGitHubClient, pb, nil) + client := NewClient(mockConfig, mockGitHubClient, pb, nil, metadata) ctx := context.Background() err = client.Download(ctx, dir, tc.light) diff --git a/pkg/db/mock_db_operation.go b/pkg/db/mock_db_operation.go new file mode 100644 index 000000000000..f0f5bd8e41b3 --- /dev/null +++ b/pkg/db/mock_db_operation.go @@ -0,0 +1,54 @@ +// Code generated by mockery v1.0.0. DO NOT EDIT. + +package db + +import ( + pkgdb "github.com/aquasecurity/trivy-db/pkg/db" + mock "github.com/stretchr/testify/mock" +) + +// mockDbOperation is an autogenerated mock type for the dbOperation type +type mockDbOperation struct { + mock.Mock +} + +type dbOperationGetMetadataReturns struct { + Metadata pkgdb.Metadata + Err error +} + +type dbOperationGetMetadataExpectation struct { + Returns dbOperationGetMetadataReturns +} + +func (_m *mockDbOperation) ApplyGetMetadataExpectation(e dbOperationGetMetadataExpectation) { + var args []interface{} + _m.On("GetMetadata", args...).Return(e.Returns.Metadata, e.Returns.Err) +} + +func (_m *mockDbOperation) ApplyGetMetadataExpectations(expectations []dbOperationGetMetadataExpectation) { + for _, e := range expectations { + _m.ApplyGetMetadataExpectation(e) + } +} + +// GetMetadata provides a mock function with given fields: +func (_m *mockDbOperation) GetMetadata() (pkgdb.Metadata, error) { + ret := _m.Called() + + var r0 pkgdb.Metadata + if rf, ok := ret.Get(0).(func() pkgdb.Metadata); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(pkgdb.Metadata) + } + + var r1 error + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} diff --git a/pkg/db/mock_operation.go b/pkg/db/mock_operation.go new file mode 100644 index 000000000000..ec397abf4cfc --- /dev/null +++ b/pkg/db/mock_operation.go @@ -0,0 +1,182 @@ +// Code generated by mockery v1.0.0. DO NOT EDIT. + +package db + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" +) + +// MockOperation is an autogenerated mock type for the Operation type +type MockOperation struct { + mock.Mock +} + +type OperationDownloadArgs struct { + Ctx context.Context + CtxAnything bool + CacheDir string + CacheDirAnything bool + Light bool + LightAnything bool +} + +type OperationDownloadReturns struct { + Err error +} + +type OperationDownloadExpectation struct { + Args OperationDownloadArgs + Returns OperationDownloadReturns +} + +func (_m *MockOperation) ApplyDownloadExpectation(e OperationDownloadExpectation) { + var args []interface{} + if e.Args.CtxAnything { + args = append(args, mock.Anything) + } else { + args = append(args, e.Args.Ctx) + } + if e.Args.CacheDirAnything { + args = append(args, mock.Anything) + } else { + args = append(args, e.Args.CacheDir) + } + if e.Args.LightAnything { + args = append(args, mock.Anything) + } else { + args = append(args, e.Args.Light) + } + _m.On("Download", args...).Return(e.Returns.Err) +} + +func (_m *MockOperation) ApplyDownloadExpectations(expectations []OperationDownloadExpectation) { + for _, e := range expectations { + _m.ApplyDownloadExpectation(e) + } +} + +// Download provides a mock function with given fields: ctx, cacheDir, light +func (_m *MockOperation) Download(ctx context.Context, cacheDir string, light bool) error { + ret := _m.Called(ctx, cacheDir, light) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, bool) error); ok { + r0 = rf(ctx, cacheDir, light) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +type OperationNeedsUpdateArgs struct { + CliVersion string + CliVersionAnything bool + Skip bool + SkipAnything bool + Light bool + LightAnything bool +} + +type OperationNeedsUpdateReturns struct { + Need bool + Err error +} + +type OperationNeedsUpdateExpectation struct { + Args OperationNeedsUpdateArgs + Returns OperationNeedsUpdateReturns +} + +func (_m *MockOperation) ApplyNeedsUpdateExpectation(e OperationNeedsUpdateExpectation) { + var args []interface{} + if e.Args.CliVersionAnything { + args = append(args, mock.Anything) + } else { + args = append(args, e.Args.CliVersion) + } + if e.Args.SkipAnything { + args = append(args, mock.Anything) + } else { + args = append(args, e.Args.Skip) + } + if e.Args.LightAnything { + args = append(args, mock.Anything) + } else { + args = append(args, e.Args.Light) + } + _m.On("NeedsUpdate", args...).Return(e.Returns.Need, e.Returns.Err) +} + +func (_m *MockOperation) ApplyNeedsUpdateExpectations(expectations []OperationNeedsUpdateExpectation) { + for _, e := range expectations { + _m.ApplyNeedsUpdateExpectation(e) + } +} + +// NeedsUpdate provides a mock function with given fields: cliVersion, skip, light +func (_m *MockOperation) NeedsUpdate(cliVersion string, skip bool, light bool) (bool, error) { + ret := _m.Called(cliVersion, skip, light) + + var r0 bool + if rf, ok := ret.Get(0).(func(string, bool, bool) bool); ok { + r0 = rf(cliVersion, skip, light) + } else { + r0 = ret.Get(0).(bool) + } + + var r1 error + if rf, ok := ret.Get(1).(func(string, bool, bool) error); ok { + r1 = rf(cliVersion, skip, light) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +type OperationUpdateMetadataArgs struct { + CacheDir string + CacheDirAnything bool +} + +type OperationUpdateMetadataReturns struct { + Err error +} + +type OperationUpdateMetadataExpectation struct { + Args OperationUpdateMetadataArgs + Returns OperationUpdateMetadataReturns +} + +func (_m *MockOperation) ApplyUpdateMetadataExpectation(e OperationUpdateMetadataExpectation) { + var args []interface{} + if e.Args.CacheDirAnything { + args = append(args, mock.Anything) + } else { + args = append(args, e.Args.CacheDir) + } + _m.On("UpdateMetadata", args...).Return(e.Returns.Err) +} + +func (_m *MockOperation) ApplyUpdateMetadataExpectations(expectations []OperationUpdateMetadataExpectation) { + for _, e := range expectations { + _m.ApplyUpdateMetadataExpectation(e) + } +} + +// UpdateMetadata provides a mock function with given fields: cacheDir +func (_m *MockOperation) UpdateMetadata(cacheDir string) error { + ret := _m.Called(cacheDir) + + var r0 error + if rf, ok := ret.Get(0).(func(string) error); ok { + r0 = rf(cacheDir) + } else { + r0 = ret.Error(0) + } + + return r0 +} diff --git a/pkg/rpc/server/inject.go b/pkg/rpc/server/inject.go index aadedcab769d..36036098bf66 100644 --- a/pkg/rpc/server/inject.go +++ b/pkg/rpc/server/inject.go @@ -24,7 +24,7 @@ func initializeLibServer() *library.Server { return &library.Server{} } -func initializeDBWorker(quiet bool) dbWorker { +func initializeDBWorker(cacheDir string, quiet bool) dbWorker { wire.Build(DBWorkerSuperSet) return dbWorker{} } diff --git a/pkg/rpc/server/listen.go b/pkg/rpc/server/listen.go index 0f2d17f429e7..ff70612e6973 100644 --- a/pkg/rpc/server/listen.go +++ b/pkg/rpc/server/listen.go @@ -48,7 +48,7 @@ func ListenAndServe(c config.Config, fsCache cache.FSCache) error { } go func() { - worker := initializeDBWorker(true) + worker := initializeDBWorker(c.CacheDir, true) ctx := context.Background() for { time.Sleep(1 * time.Hour) @@ -99,7 +99,8 @@ func newDBWorker(dbClient dbFile.Operation) dbWorker { func (w dbWorker) update(ctx context.Context, appVersion, cacheDir string, dbUpdateWg, requestWg *sync.WaitGroup) error { - needsUpdate, err := w.dbClient.NeedsUpdate(ctx, appVersion, false, false) + log.Logger.Debug("Check for DB update...") + needsUpdate, err := w.dbClient.NeedsUpdate(appVersion, false, false) if err != nil { return xerrors.Errorf("failed to check if db needs an update") } else if !needsUpdate { @@ -139,6 +140,10 @@ func (w dbWorker) hotUpdate(ctx context.Context, cacheDir string, dbUpdateWg, re return xerrors.Errorf("failed to copy the database file: %w", err) } + if err = w.dbClient.UpdateMetadata(cacheDir); err != nil { + return xerrors.Errorf("unable to update database metadata: %w", err) + } + log.Logger.Info("Reopening DB...") if err = db.Init(cacheDir); err != nil { return xerrors.Errorf("failed to open DB: %w", err) diff --git a/pkg/rpc/server/listen_test.go b/pkg/rpc/server/listen_test.go index 1f6af1ad039c..01309701d5bd 100644 --- a/pkg/rpc/server/listen_test.go +++ b/pkg/rpc/server/listen_test.go @@ -112,10 +112,11 @@ func Test_dbWorker_update(t *testing.T) { require.NoError(t, db.Init(cacheDir), tt.name) - mockDBClient := new(dbFile.MockClient) - mockDBClient.On("NeedsUpdate", mock.Anything, + mockDBClient := new(dbFile.MockOperation) + mockDBClient.On("NeedsUpdate", tt.needsUpdate.input.appVersion, false, tt.needsUpdate.input.skip).Return( tt.needsUpdate.output.needsUpdate, tt.needsUpdate.output.err) + mockDBClient.On("UpdateMetadata", mock.Anything).Return(nil) if tt.download.call { mockDBClient.On("Download", mock.Anything, mock.Anything, false).Run( diff --git a/pkg/rpc/server/wire_gen.go b/pkg/rpc/server/wire_gen.go index eedd67028087..4133f02f8fcd 100644 --- a/pkg/rpc/server/wire_gen.go +++ b/pkg/rpc/server/wire_gen.go @@ -18,6 +18,7 @@ import ( ospkg2 "github.com/aquasecurity/trivy/pkg/rpc/server/ospkg" "github.com/aquasecurity/trivy/pkg/scanner/local" "github.com/aquasecurity/trivy/pkg/vulnerability" + "github.com/spf13/afero" "k8s.io/utils/clock" ) @@ -52,12 +53,14 @@ func initializeLibServer() *library2.Server { return server } -func initializeDBWorker(quiet bool) dbWorker { +func initializeDBWorker(cacheDir string, quiet bool) dbWorker { config := db.Config{} client := github.NewClient() progressBar := indicator.NewProgressBar(quiet) realClock := clock.RealClock{} - dbClient := db2.NewClient(config, client, progressBar, realClock) + fs := afero.NewOsFs() + metadata := db2.NewMetadata(fs, cacheDir) + dbClient := db2.NewClient(config, client, progressBar, realClock, metadata) serverDbWorker := newDBWorker(dbClient) return serverDbWorker } diff --git a/pkg/types/docker_conf.go b/pkg/types/docker_conf.go index 1390c4a5e56d..be6ff28b997d 100644 --- a/pkg/types/docker_conf.go +++ b/pkg/types/docker_conf.go @@ -11,7 +11,7 @@ type DockerConfig struct { UserName string `env:"TRIVY_USERNAME"` Password string `env:"TRIVY_PASSWORD"` Insecure bool `env:"TRIVY_INSECURE" envDefault:"false"` - NonSSL bool `env:"TRIVY_NONSSL" envDefault:"false"` + NonSSL bool `env:"TRIVY_NON_SSL" envDefault:"false"` } func GetDockerOption(timeout time.Duration) (types.DockerOption, error) {