diff --git a/errors/errors.go b/errors/errors.go index 915b0628..dd3f82e5 100644 --- a/errors/errors.go +++ b/errors/errors.go @@ -9,6 +9,7 @@ var ( ErrRepoBadVersion = errors.New("repository: unsupported layout version") ErrManifestNotFound = errors.New("manifest: not found") ErrBadManifest = errors.New("manifest: invalid contents") + ErrBadIndex = errors.New("index: invalid contents") ErrUploadNotFound = errors.New("uploads: not found") ErrBadUploadRange = errors.New("uploads: bad range") ErrBlobNotFound = errors.New("blob: not found") @@ -40,4 +41,5 @@ var ( ErrInvalidRoute = errors.New("routes: invalid route prefix") ErrImgStoreNotFound = errors.New("routes: image store not found corresponding to given route") ErrEmptyValue = errors.New("cache: empty value") + ErrEmptyRepoList = errors.New("search: no repository found") ) diff --git a/go.mod b/go.mod index 2e4949e1..fe974e35 100644 --- a/go.mod +++ b/go.mod @@ -3,32 +3,28 @@ module github.com/anuvu/zot go 1.16 require ( - github.com/99designs/gqlgen v0.12.2 - github.com/AdaLogics/go-fuzz-headers v0.0.0-20210921152813-f50b76b2163b // indirect + github.com/99designs/gqlgen v0.13.0 github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 github.com/apex/log v1.9.0 github.com/aquasecurity/trivy v0.0.0-00010101000000-000000000000 - github.com/briandowns/spinner v1.12.0 + github.com/briandowns/spinner v1.16.0 github.com/chartmuseum/auth v0.5.0 - github.com/containerd/containerd v1.5.4 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect github.com/dustin/go-humanize v1.0.0 - github.com/fsnotify/fsnotify v1.4.9 + github.com/fsnotify/fsnotify v1.5.1 github.com/getlantern/deepcopy v0.0.0-20160317154340-7f45deb8130a - github.com/go-ldap/ldap/v3 v3.3.0 + github.com/go-ldap/ldap/v3 v3.4.1 github.com/gofrs/uuid v4.0.0+incompatible github.com/google/go-containerregistry v0.6.0 github.com/gorilla/handlers v1.5.1 github.com/gorilla/mux v1.8.0 - github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/json-iterator/go v1.1.11 github.com/klauspost/compress v1.13.6 // indirect github.com/mitchellh/mapstructure v1.4.1 github.com/moby/sys/mount v0.2.0 // indirect - github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484 // indirect - github.com/nmcclain/ldap v0.0.0-20191021200707-3b3b69a7e9e3 + github.com/nmcclain/ldap v0.0.0-20210720162743-7f8d1e44eeba github.com/olekukonko/tablewriter v0.0.5 - github.com/opencontainers/distribution-spec/specs-go v0.0.0-20210810194746-13fa739db32c + github.com/opencontainers/distribution-spec/specs-go v0.0.0-20210830161531-162b5c95788b github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6 github.com/opencontainers/umoci v0.4.8-0.20210922062158-e60a0cc726e6 diff --git a/go.sum b/go.sum index 4f50637f..eca19347 100644 --- a/go.sum +++ b/go.sum @@ -40,11 +40,10 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/99designs/gqlgen v0.12.2 h1:aOdpsiCycFtCnAv8CAI1exnKrIDHMqtMzQoXeTziY4o= -github.com/99designs/gqlgen v0.12.2/go.mod h1:7zdGo6ry9u1YBp/qlb2uxSU5Mt2jQKLcBETQiKk+Bxo= +github.com/99designs/gqlgen v0.13.0 h1:haLTcUp3Vwp80xMVEg5KRNwzfUrgFdRmtBY8fuB8scA= +github.com/99designs/gqlgen v0.13.0/go.mod h1:NV130r6f4tpRWuAI+zsrSdooO/eWUv+Gyyoi3rEfXIk= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20210401092550-0a8691dafd0d h1:oXbCfnomBQyeTWN6RNHmMUrmzyUGLYoF2OOcfkpoCHE= github.com/AdaLogics/go-fuzz-headers v0.0.0-20210401092550-0a8691dafd0d/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg= -github.com/AdaLogics/go-fuzz-headers v0.0.0-20210921152813-f50b76b2163b h1:eFb6EtuUv+MRaLzNRldt6ofzuxallkY+5mqT2cdakjs= -github.com/AdaLogics/go-fuzz-headers v0.0.0-20210921152813-f50b76b2163b/go.mod h1:WpB7kf89yJUETZxQnP1kgYPNwlT2jjdDYUCoxVggM3g= github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= @@ -103,11 +102,8 @@ github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEY github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8= github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg= github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00= +github.com/Microsoft/hcsshim v0.8.16 h1:8/auA4LFIZFTGrqfKhGBSXwM6/4X1fHa/xniyEHu8ac= github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600= -github.com/Microsoft/hcsshim v0.8.17 h1:yFHH5bghP9ij5Y34PPaMOE8g//oXZ0uJQeMENVo2zcI= -github.com/Microsoft/hcsshim v0.8.17/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4= -github.com/Microsoft/hcsshim v0.8.18 h1:cYnKADiM1869gvBpos3YCteeT6sZLB48lB5dmMMs8Tg= -github.com/Microsoft/hcsshim v0.8.18/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4= github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU= github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= @@ -178,7 +174,6 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= -github.com/bits-and-blooms/bitset v1.2.0 h1:Kn4yilvwNtMACtf1eYDlG8H77R07mZSPbMjLyS07ChA= github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= @@ -186,8 +181,8 @@ github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnweb github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/briandowns/spinner v0.0.0-20190319032542-ac46072a5a91/go.mod h1:hw/JEQBIE+c/BLI4aKM8UU8v+ZqrD3h7HC27kKt8JQU= -github.com/briandowns/spinner v1.12.0 h1:72O0PzqGJb6G3KgrcIOtL/JAGGZ5ptOMCn9cUHmqsmw= -github.com/briandowns/spinner v1.12.0/go.mod h1:QOuQk7x+EaDASo80FEXwlwiA+j/PPIcX3FScO+3/ZPQ= +github.com/briandowns/spinner v1.16.0 h1:DFmp6hEaIx2QXXuqSJmtfSBSAjRmpGiKG6ip2Wm/yOs= +github.com/briandowns/spinner v1.16.0/go.mod h1:QOuQk7x+EaDASo80FEXwlwiA+j/PPIcX3FScO+3/ZPQ= github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= @@ -252,25 +247,20 @@ github.com/containerd/containerd v1.5.0-beta.1/go.mod h1:5HfvG1V2FsKesEGQ17k5/T7 github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo/uBBoBORwEx6ardVcmKU= github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI= github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s= -github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g= github.com/containerd/containerd v1.5.2 h1:MG/Bg1pbmMb61j3wHCFWPxESXHieiKr2xG64px/k8zQ= github.com/containerd/containerd v1.5.2/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g= -github.com/containerd/containerd v1.5.4 h1:uPF0og3ByFzDnaStfiQj3fVGTEtaSNyU+bW7GR/nqGA= -github.com/containerd/containerd v1.5.4/go.mod h1:sx18RgvW6ABJ4iYUw7Q5x7bgFOAB9B6G7+yO0XBc4zw= github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe/go.mod h1:cECdGN1O8G9bgKTlLhuPJimka6Xb/Gg7vYzCTNVxhvo= github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y= github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ= -github.com/containerd/continuity v0.1.0 h1:UFRRY5JemiAhPZrr/uE0n8fMTLcZsUvySPr1+D7pgr8= github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM= github.com/containerd/fifo v0.0.0-20180307165137-3d5202aec260/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= github.com/containerd/fifo v0.0.0-20200410184934-f15a3290365b/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= github.com/containerd/fifo v0.0.0-20201026212402-0724c46b320c/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= github.com/containerd/fifo v0.0.0-20210316144830-115abcc95a1d/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= -github.com/containerd/fifo v1.0.0 h1:6PirWBr9/L7GDamKr+XM0IeUFXu5mf3M/BPpH9gaLBU= github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= github.com/containerd/go-cni v1.0.1/go.mod h1:+vUpYxKvAF72G9i1WoDOiPGRtQpqsNW/ZHtSlv++smU= github.com/containerd/go-cni v1.0.2/go.mod h1:nrNABBHzu0ZwCug9Ije8hL2xBCYh/pjfMb1aZGrrohk= @@ -292,12 +282,10 @@ github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDG github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8= github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= -github.com/containerd/ttrpc v1.0.2 h1:2/O3oTZN36q2xRolk0a2WWGgh7/Vf/liElg5hFYLX9U= github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk= github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg= -github.com/containerd/typeurl v1.0.2 h1:Chlt8zIieDbzQFzXzAeBEF92KhExuE4p9p92/QmY7aY= github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s= github.com/containerd/zfs v0.0.0-20200918131355-0a33824f23a2/go.mod h1:8IgZOBdv8fAgXddBT4dBXJPtxyRsejFIpXoklgxgEjw= github.com/containerd/zfs v0.0.0-20210301145711-11e8f1707f62/go.mod h1:A9zfAbMlQwE+/is6hi0Xw8ktpL+6glmqZYtevJgaB8Y= @@ -375,7 +363,6 @@ github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avu github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= -github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8= github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= @@ -388,7 +375,6 @@ github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3 github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dvyukov/go-fuzz v0.0.0-20210914135545-4980593459a1/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f h1:8GDPb0tCY8LQ+OJ3dbHb5sA6YZWXFORQYZx5sdsTlMs= @@ -416,8 +402,9 @@ github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= +github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/getlantern/deepcopy v0.0.0-20160317154340-7f45deb8130a h1:yU/FENpkHYISWsQrbr3pcZOBj0EuRjPzNc1+dTCLu44= @@ -449,8 +436,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2 github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-ldap/ldap/v3 v3.3.0 h1:lwx+SJpgOHd8tG6SumBQZXCmNX51zM8B1cfxJ5gv4tQ= -github.com/go-ldap/ldap/v3 v3.3.0/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= +github.com/go-ldap/ldap/v3 v3.4.1 h1:fU/0xli6HY02ocbMuozHAYsaHLcnkLjvho2r5a34BUU= +github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= @@ -492,7 +479,6 @@ github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU= -github.com/gogo/googleapis v1.4.0 h1:zgVt4UpGxcqVOw97aRGxT4svlcmdK35fynLNctY32zI= github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -588,7 +574,6 @@ github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3 github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/wire v0.3.0 h1:imGQZGEVEHpje5056+K+cgdO72p0LQv2xIIFXNGUf60= github.com/google/wire v0.3.0/go.mod h1:i1DMg/Lu8Sz5yYl25iOdmc5CT5qusaa+zmRWs16741s= @@ -634,9 +619,8 @@ github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjh github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= -github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= -github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= @@ -788,7 +772,6 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= -github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= github.com/moby/sys/mount v0.2.0 h1:WhCW5B355jtxndN5ovugJlMFJawbUODuW8fSnEH6SSM= github.com/moby/sys/mount v0.2.0/go.mod h1:aAivFE2LB3W4bACsUXChRHQ0qKWsetY4Y9V7sxOougM= @@ -820,8 +803,8 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWb github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484 h1:D9EvfGQvlkKaDr2CRKN++7HbSXbefUNDrPq60T+g24s= github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484/go.mod h1:O1EljZ+oHprtxDDPHiMWVo/5dBT6PlvWX5PSwj80aBA= -github.com/nmcclain/ldap v0.0.0-20191021200707-3b3b69a7e9e3 h1:NNis9uuNpG5h97Dvxxo53Scg02qBg+3Nfabg6zjFGu8= -github.com/nmcclain/ldap v0.0.0-20191021200707-3b3b69a7e9e3/go.mod h1:YtrVB1/v9Td9SyjXpjYVmbdKgj9B0nPTBsdGUxy0i8U= +github.com/nmcclain/ldap v0.0.0-20210720162743-7f8d1e44eeba h1:DO8NFYdcRv1dnyAINJIBm6Bw2XibtLvQniNFGzf2W8E= +github.com/nmcclain/ldap v0.0.0-20210720162743-7f8d1e44eeba/go.mod h1:4S0XndRL8HNOaQBfdViJ2F/GPCgL524xlXRuXFH12/U= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= @@ -845,8 +828,8 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= github.com/open-policy-agent/opa v0.21.1 h1:c4lUnB0mO2KssiUnyh6Y9IGhggvXI3EgObkmhVTvEqQ= github.com/open-policy-agent/opa v0.21.1/go.mod h1:cZaTfhxsj7QdIiUI0U9aBtOLLTqVNe+XE60+9kZKLHw= -github.com/opencontainers/distribution-spec/specs-go v0.0.0-20210810194746-13fa739db32c h1:v9HHyeBaIUQsl+1q73JthiG5t4OoWeN9IjlkzwFz3ek= -github.com/opencontainers/distribution-spec/specs-go v0.0.0-20210810194746-13fa739db32c/go.mod h1:aA4vdXRS8E1TG7pLZOz85InHi3BiPdErh8IpJN6E0x4= +github.com/opencontainers/distribution-spec/specs-go v0.0.0-20210830161531-162b5c95788b h1:uFT5KpymBH31VQRcA1bf19zWHVMJqsGXPrOMJVOX4bA= +github.com/opencontainers/distribution-spec/specs-go v0.0.0-20210830161531-162b5c95788b/go.mod h1:aA4vdXRS8E1TG7pLZOz85InHi3BiPdErh8IpJN6E0x4= github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= @@ -874,7 +857,6 @@ github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.m github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE= github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= -github.com/opencontainers/selinux v1.8.2 h1:c4ca10UMgRcvZ6h0K4HtS15UaVSBEaE+iln2LVpAuGc= github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= github.com/opencontainers/umoci v0.4.8-0.20210922062158-e60a0cc726e6 h1:yRmw/21YcR/78dRoFyWNJ6c3VxOXqe97PhNZI0Ib7bM= github.com/opencontainers/umoci v0.4.8-0.20210922062158-e60a0cc726e6/go.mod h1:kO0Bh4G4BZUh2QSlqsCR/OCtdqLjmt3mvD6okZhMBlU= @@ -1081,9 +1063,7 @@ github.com/vbatts/go-mtree v0.5.0 h1:dM+5XZdqH0j9CSZeerhoN/tAySdwnmevaZHO1XGW2Vc github.com/vbatts/go-mtree v0.5.0/go.mod h1:7JbaNHyBMng+RP8C3Q4E+4Ca8JnGQA2R/MB+jb4tSOk= github.com/vdemeester/k8s-pkg-credentialprovider v1.17.4/go.mod h1:inCTmtUdr5KJbreVojo06krnTgaeAz/Z7lynpPk/Q2c= github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e/go.mod h1:/HUdMve7rvxZma+2ZELQeNh88+003LL7Pf/CZ089j8U= -github.com/vektah/gqlparser v1.3.1 h1:8b0IcD3qZKWJQHSzynbDlrtP3IxVydZ2DZepCGofqfU= -github.com/vektah/gqlparser v1.3.1/go.mod h1:bkVf0FX+Stjg/MHnm8mEyubuaArhNEqfQhF+OTiAL74= -github.com/vektah/gqlparser/v2 v2.0.1/go.mod h1:SyUiHgLATUR8BiYURfTirrTcGpcE+4XkV2se04Px1Ms= +github.com/vektah/gqlparser/v2 v2.1.0/go.mod h1:SyUiHgLATUR8BiYURfTirrTcGpcE+4XkV2se04Px1Ms= github.com/vektah/gqlparser/v2 v2.2.0 h1:bAc3slekAAJW6sZTi07aGq0OrfaCjj4jxARAaC7g2EM= github.com/vektah/gqlparser/v2 v2.2.0/go.mod h1:i3mQIGIrbK2PD1RrCeMTlVbkF2FJ6WkU1KJlJlC+3F4= github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= @@ -1384,6 +1364,7 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210923061019-b8560ed6a9b7 h1:c20P3CcPbopVp2f7099WLOqSNKURf30Z0uq66HpijZY= golang.org/x/sys v0.0.0-20210923061019-b8560ed6a9b7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= diff --git a/pkg/extensions/extensions.go b/pkg/extensions/extensions.go index ca357d89..a263d333 100644 --- a/pkg/extensions/extensions.go +++ b/pkg/extensions/extensions.go @@ -60,7 +60,14 @@ func SetupRoutes(extension *ExtensionConfig, router *mux.Router, storeController log.Info().Msg("setting up extensions routes") if extension.Search != nil && extension.Search.Enable { - resConfig := search.GetResolverConfig(log, storeController) + var resConfig search.Config + + if extension.Search.CVE != nil { + resConfig = search.GetResolverConfig(log, storeController, true) + } else { + resConfig = search.GetResolverConfig(log, storeController, false) + } + router.PathPrefix("/query").Methods("GET", "POST"). Handler(gqlHandler.NewDefaultServer(search.NewExecutableSchema(resConfig))) } diff --git a/pkg/extensions/search/common/common.go b/pkg/extensions/search/common/common.go new file mode 100644 index 00000000..6a1cd478 --- /dev/null +++ b/pkg/extensions/search/common/common.go @@ -0,0 +1,155 @@ +package common + +import ( + "fmt" + "path" + "sort" + "strings" + "time" + + "github.com/anuvu/zot/pkg/storage" + ispec "github.com/opencontainers/image-spec/specs-go/v1" +) + +const ( + AnnotationLabels = "org.label-schema.labels" + LabelAnnotationCreated = "org.label-schema.build-date" + LabelAnnotationVendor = "org.label-schema.vendor" + LabelAnnotationDescription = "org.label-schema.description" + LabelAnnotationLicenses = "org.label-schema.license" +) + +type TagInfo struct { + Name string + Digest string + Timestamp time.Time +} + +func GetImageRepoPath(image string, storeController storage.StoreController) string { + rootDir := GetRootDir(image, storeController) + + repo := GetRepo(image) + + return path.Join(rootDir, repo) +} + +func GetRootDir(image string, storeController storage.StoreController) string { + var rootDir string + + prefixName := GetRoutePrefix(image) + + subStore := storeController.SubStore + + if subStore != nil { + imgStore, ok := storeController.SubStore[prefixName] + if ok { + rootDir = imgStore.RootDir() + } else { + rootDir = storeController.DefaultStore.RootDir() + } + } else { + rootDir = storeController.DefaultStore.RootDir() + } + + return rootDir +} + +func GetRepo(image string) string { + if strings.Contains(image, ":") { + splitString := strings.SplitN(image, ":", 2) + if len(splitString) != 2 { //nolint: gomnd + return image + } + + return splitString[0] + } + + return image +} + +func GetFixedTags(allTags []TagInfo, infectedTags []TagInfo) []TagInfo { + sort.Slice(allTags, func(i, j int) bool { + return allTags[i].Timestamp.Before(allTags[j].Timestamp) + }) + + latestInfected := TagInfo{} + + for _, tag := range infectedTags { + if !tag.Timestamp.Before(latestInfected.Timestamp) { + latestInfected = tag + } + } + + var fixedTags []TagInfo + + for _, tag := range allTags { + if tag.Timestamp.After(latestInfected.Timestamp) { + fixedTags = append(fixedTags, tag) + } + } + + return fixedTags +} + +func GetLatestTag(allTags []TagInfo) TagInfo { + sort.Slice(allTags, func(i, j int) bool { + return allTags[i].Timestamp.Before(allTags[j].Timestamp) + }) + + return allTags[len(allTags)-1] +} + +func GetRoutePrefix(name string) string { + names := strings.SplitN(name, "/", 2) + + if len(names) != 2 { // nolint: gomnd + // it means route is of global storage e.g "centos:latest" + if len(names) == 1 { + return "/" + } + } + + return fmt.Sprintf("/%s", names[0]) +} + +func GetDescription(labels map[string]string) string { + desc, ok := labels[ispec.AnnotationDescription] + if !ok { + desc, ok = labels[LabelAnnotationDescription] + if !ok { + desc = "" + } + } + + return desc +} + +func GetLicense(labels map[string]string) string { + license, ok := labels[ispec.AnnotationLicenses] + if !ok { + license, ok = labels[LabelAnnotationLicenses] + if !ok { + license = "" + } + } + + return license +} + +func GetVendor(labels map[string]string) string { + vendor, ok := labels[ispec.AnnotationVendor] + if !ok { + vendor, ok = labels[LabelAnnotationVendor] + if !ok { + vendor = "" + } + } + + return vendor +} + +func GetCategories(labels map[string]string) string { + categories := labels[AnnotationLabels] + + return categories +} diff --git a/pkg/extensions/search/common/common_test.go b/pkg/extensions/search/common/common_test.go new file mode 100644 index 00000000..b0ddb5cd --- /dev/null +++ b/pkg/extensions/search/common/common_test.go @@ -0,0 +1,460 @@ +package common_test + +import ( + "context" + "encoding/json" + "io" + "io/ioutil" + "os" + "path" + "testing" + "time" + + "github.com/anuvu/zot/pkg/api" + ext "github.com/anuvu/zot/pkg/extensions" + "github.com/anuvu/zot/pkg/extensions/search/common" + "github.com/anuvu/zot/pkg/log" + "github.com/anuvu/zot/pkg/storage" + ispec "github.com/opencontainers/image-spec/specs-go/v1" + . "github.com/smartystreets/goconvey/convey" + "gopkg.in/resty.v1" +) + +// nolint:gochecknoglobals +var ( + rootDir string + subRootDir string +) + +const ( + BaseURL1 = "http://127.0.0.1:8085" + Port1 = "8085" +) + +type ImgResponsWithLatestTag struct { + ImgListWithLatestTag ImgListWithLatestTag `json:"data"` + Errors []ErrorGQL `json:"errors"` +} + +type ImgListWithLatestTag struct { + Images []ImageInfo `json:"ImageListWithLatestTag"` +} + +type ErrorGQL struct { + Message string `json:"message"` + Path []string `json:"path"` +} + +type ImageInfo struct { + Name string + Latest string + LastUpdated time.Time + Description string + Licenses string + Vendor string + Size string + Labels string +} + +func testSetup() error { + dir, err := ioutil.TempDir("", "search_test") + if err != nil { + return err + } + + subDir, err := ioutil.TempDir("", "sub_search_test") + if err != nil { + return err + } + + rootDir = dir + + subRootDir = subDir + + err = copyFiles("../../../../test/data", rootDir) + if err != nil { + return err + } + + err = copyFiles("../../../../test/data", subDir) + if err != nil { + return err + } + + return nil +} + +func getTags() ([]common.TagInfo, []common.TagInfo) { + tags := make([]common.TagInfo, 0) + + firstTag := common.TagInfo{Name: "1.0.0", + Digest: "sha256:eca04f027f414362596f2632746d8a178362170b9ac9af772011fedcc3877ebb", + Timestamp: time.Now()} + secondTag := common.TagInfo{Name: "1.0.1", + Digest: "sha256:eca04f027f414362596f2632746d8a179362170b9ac9af772011fedcc3877ebb", + Timestamp: time.Now()} + thirdTag := common.TagInfo{Name: "1.0.2", + Digest: "sha256:eca04f027f414362596f2632746d8a170362170b9ac9af772011fedcc3877ebb", + Timestamp: time.Now()} + fourthTag := common.TagInfo{Name: "1.0.3", + Digest: "sha256:eca04f027f414362596f2632746d8a171362170b9ac9af772011fedcc3877ebb", + Timestamp: time.Now()} + + tags = append(tags, firstTag, secondTag, thirdTag, fourthTag) + + infectedTags := make([]common.TagInfo, 0) + infectedTags = append(infectedTags, secondTag) + + return tags, infectedTags +} + +func copyFiles(sourceDir string, destDir string) error { + sourceMeta, err := os.Stat(sourceDir) + if err != nil { + return err + } + + if err := os.MkdirAll(destDir, sourceMeta.Mode()); err != nil { + return err + } + + files, err := ioutil.ReadDir(sourceDir) + if err != nil { + return err + } + + for _, file := range files { + sourceFilePath := path.Join(sourceDir, file.Name()) + destFilePath := path.Join(destDir, file.Name()) + + if file.IsDir() { + if err = copyFiles(sourceFilePath, destFilePath); err != nil { + return err + } + } else { + sourceFile, err := os.Open(sourceFilePath) + if err != nil { + return err + } + defer sourceFile.Close() + + destFile, err := os.Create(destFilePath) + if err != nil { + return err + } + defer destFile.Close() + + if _, err = io.Copy(destFile, sourceFile); err != nil { + return err + } + } + } + + return nil +} + +func TestImageFormat(t *testing.T) { + Convey("Test valid image", t, func() { + log := log.NewLogger("debug", "") + dbDir := "../../../../test/data" + olu := common.NewOciLayoutUtils(log) + isValidImage, err := olu.IsValidImageFormat(path.Join(dbDir, "zot-test")) + So(err, ShouldBeNil) + So(isValidImage, ShouldEqual, true) + + isValidImage, err = olu.IsValidImageFormat(path.Join(dbDir, "zot-test:0.0.1")) + So(err, ShouldBeNil) + So(isValidImage, ShouldEqual, true) + + isValidImage, err = olu.IsValidImageFormat(path.Join(dbDir, "zot-test:0.0.")) + So(err, ShouldBeNil) + So(isValidImage, ShouldEqual, false) + + isValidImage, err = olu.IsValidImageFormat(path.Join(dbDir, "zot-noindex-test")) + So(err, ShouldNotBeNil) + So(isValidImage, ShouldEqual, false) + + isValidImage, err = olu.IsValidImageFormat(path.Join(dbDir, "zot--tet")) + So(err, ShouldNotBeNil) + So(isValidImage, ShouldEqual, false) + + isValidImage, err = olu.IsValidImageFormat(path.Join(dbDir, "zot-noindex-test")) + So(err, ShouldNotBeNil) + So(isValidImage, ShouldEqual, false) + + isValidImage, err = olu.IsValidImageFormat(path.Join(dbDir, "zot-squashfs-noblobs")) + So(err, ShouldNotBeNil) + So(isValidImage, ShouldEqual, false) + + isValidImage, err = olu.IsValidImageFormat(path.Join(dbDir, "zot-squashfs-invalid-index")) + So(err, ShouldNotBeNil) + So(isValidImage, ShouldEqual, false) + + isValidImage, err = olu.IsValidImageFormat(path.Join(dbDir, "zot-squashfs-invalid-blob")) + So(err, ShouldNotBeNil) + So(isValidImage, ShouldEqual, false) + + isValidImage, err = olu.IsValidImageFormat(path.Join(dbDir, "zot-squashfs-test:0.3.22-squashfs")) + So(err, ShouldNotBeNil) + So(isValidImage, ShouldEqual, false) + + isValidImage, err = olu.IsValidImageFormat(path.Join(dbDir, "zot-nonreadable-test")) + So(err, ShouldNotBeNil) + So(isValidImage, ShouldEqual, false) + }) +} + +func TestLatestTagSearchHTTP(t *testing.T) { + Convey("Test latest image search by timestamp", t, func() { + err := testSetup() + if err != nil { + panic(err) + } + config := api.NewConfig() + config.HTTP.Port = Port1 + config.Storage.RootDirectory = rootDir + config.Storage.SubPaths = make(map[string]api.StorageConfig) + config.Storage.SubPaths["/a"] = api.StorageConfig{RootDirectory: subRootDir} + config.Extensions = &ext.ExtensionConfig{ + Search: &ext.SearchConfig{Enable: true}, + } + + config.Extensions.Search.CVE = nil + + c := api.NewController(config) + + go func() { + // this blocks + if err := c.Run(); err != nil { + return + } + }() + + // wait till ready + for { + _, err := resty.R().Get(BaseURL1) + if err == nil { + break + } + time.Sleep(100 * time.Millisecond) + } + + // shut down server + defer func() { + ctx := context.Background() + _ = c.Server.Shutdown(ctx) + }() + + resp, err := resty.R().Get(BaseURL1 + "/v2/") + So(resp, ShouldNotBeNil) + So(err, ShouldBeNil) + So(resp.StatusCode(), ShouldEqual, 200) + + resp, err = resty.R().Get(BaseURL1 + "/query") + So(resp, ShouldNotBeNil) + So(err, ShouldBeNil) + So(resp.StatusCode(), ShouldEqual, 200) + + resp, err = resty.R().Get(BaseURL1 + "/query?query={ImageListWithLatestTag(){Name%20Latest}}") + So(resp, ShouldNotBeNil) + So(err, ShouldBeNil) + So(resp.StatusCode(), ShouldEqual, 200) + + var responseStruct ImgResponsWithLatestTag + err = json.Unmarshal(resp.Body(), &responseStruct) + So(err, ShouldBeNil) + So(len(responseStruct.ImgListWithLatestTag.Images), ShouldEqual, 4) + + images := responseStruct.ImgListWithLatestTag.Images + So(images[0].Latest, ShouldEqual, "0.0.1") + + resp, err = resty.R().Get(BaseURL1 + "/query?query={ImageListWithLatestTag(){Name%20Latest}}") + So(resp, ShouldNotBeNil) + So(err, ShouldBeNil) + + err = os.Chmod(rootDir, 0000) + if err != nil { + panic(err) + } + + resp, err = resty.R().Get(BaseURL1 + "/query?query={ImageListWithLatestTag(){Name%20Latest}}") + So(resp, ShouldNotBeNil) + So(err, ShouldBeNil) + So(resp.StatusCode(), ShouldEqual, 200) + + err = json.Unmarshal(resp.Body(), &responseStruct) + So(err, ShouldBeNil) + So(len(responseStruct.ImgListWithLatestTag.Images), ShouldEqual, 0) + + err = os.Chmod(rootDir, 0755) + if err != nil { + panic(err) + } + + // Delete config blob and try. + err = os.Remove(path.Join(subRootDir, "zot-test/blobs/sha256", + "adf3bb6cc81f8bd6a9d5233be5f0c1a4f1e3ed1cf5bbdfad7708cc8d4099b741")) + if err != nil { + panic(err) + } + + resp, err = resty.R().Get(BaseURL1 + "/query?query={ImageListWithLatestTag(){Name%20Latest}}") + So(resp, ShouldNotBeNil) + So(err, ShouldBeNil) + So(resp.StatusCode(), ShouldEqual, 200) + + err = os.Remove(path.Join(subRootDir, "zot-test/blobs/sha256", + "2bacca16b9df395fc855c14ccf50b12b58d35d468b8e7f25758aff90f89bf396")) + if err != nil { + panic(err) + } + + resp, err = resty.R().Get(BaseURL1 + "/query?query={ImageListWithLatestTag(){Name%20Latest}}") + So(resp, ShouldNotBeNil) + So(err, ShouldBeNil) + So(resp.StatusCode(), ShouldEqual, 200) + + err = os.Remove(path.Join(rootDir, "zot-test/blobs/sha256", + "adf3bb6cc81f8bd6a9d5233be5f0c1a4f1e3ed1cf5bbdfad7708cc8d4099b741")) + if err != nil { + panic(err) + } + + resp, err = resty.R().Get(BaseURL1 + "/query?query={ImageListWithLatestTag(){Name%20Latest}}") + So(resp, ShouldNotBeNil) + So(err, ShouldBeNil) + So(resp.StatusCode(), ShouldEqual, 200) + + // Delete manifest blob also and try + err = os.Remove(path.Join(rootDir, "zot-test/blobs/sha256", + "2bacca16b9df395fc855c14ccf50b12b58d35d468b8e7f25758aff90f89bf396")) + if err != nil { + panic(err) + } + + resp, err = resty.R().Get(BaseURL1 + "/query?query={ImageListWithLatestTag(){Name%20Latest}}") + So(resp, ShouldNotBeNil) + So(err, ShouldBeNil) + So(resp.StatusCode(), ShouldEqual, 200) + }) +} + +func TestUtilsMethod(t *testing.T) { + Convey("Test utils", t, func() { + // Test GetRepo method + repo := common.GetRepo("test") + So(repo, ShouldEqual, "test") + + repo = common.GetRepo(":") + So(repo, ShouldEqual, "") + + repo = common.GetRepo("") + So(repo, ShouldEqual, "") + + repo = common.GetRepo("test:123") + So(repo, ShouldEqual, "test") + + repo = common.GetRepo("a/test:123") + So(repo, ShouldEqual, "a/test") + + repo = common.GetRepo("a/test:123:456") + So(repo, ShouldEqual, "a/test") + + // Test various labels + labels := make(map[string]string) + + desc := common.GetDescription(labels) + So(desc, ShouldEqual, "") + + license := common.GetLicense(labels) + So(license, ShouldEqual, "") + + vendor := common.GetVendor(labels) + So(vendor, ShouldEqual, "") + + categories := common.GetCategories(labels) + So(categories, ShouldEqual, "") + + labels[ispec.AnnotationVendor] = "zot" + labels[ispec.AnnotationDescription] = "zot-desc" + labels[ispec.AnnotationLicenses] = "zot-license" + labels[common.AnnotationLabels] = "zot-labels" + + desc = common.GetDescription(labels) + So(desc, ShouldEqual, "zot-desc") + + license = common.GetLicense(labels) + So(license, ShouldEqual, "zot-license") + + vendor = common.GetVendor(labels) + So(vendor, ShouldEqual, "zot") + + categories = common.GetCategories(labels) + So(categories, ShouldEqual, "zot-labels") + + labels = make(map[string]string) + + // Use diff key + labels[common.LabelAnnotationVendor] = "zot-vendor" + labels[common.LabelAnnotationDescription] = "zot-label-desc" + labels[common.LabelAnnotationLicenses] = "zot-label-license" + + desc = common.GetDescription(labels) + So(desc, ShouldEqual, "zot-label-desc") + + license = common.GetLicense(labels) + So(license, ShouldEqual, "zot-label-license") + + vendor = common.GetVendor(labels) + So(vendor, ShouldEqual, "zot-vendor") + + routePrefix := common.GetRoutePrefix("test:latest") + So(routePrefix, ShouldEqual, "/") + + routePrefix = common.GetRoutePrefix("a/test:latest") + So(routePrefix, ShouldEqual, "/a") + + routePrefix = common.GetRoutePrefix("a/b/test:latest") + So(routePrefix, ShouldEqual, "/a") + + allTags, infectedTags := getTags() + + latestTag := common.GetLatestTag(allTags) + So(latestTag.Name, ShouldEqual, "1.0.3") + + fixedTags := common.GetFixedTags(allTags, infectedTags) + So(len(fixedTags), ShouldEqual, 2) + + log := log.NewLogger("debug", "") + + rootDir, err := ioutil.TempDir("", "common_utils_test") + if err != nil { + panic(err) + } + defer os.RemoveAll(rootDir) + + subRootDir, err := ioutil.TempDir("", "common_utils_test") + if err != nil { + panic(err) + } + defer os.RemoveAll(subRootDir) + + defaultStore := storage.NewImageStore(rootDir, false, false, log) + + subStore := storage.NewImageStore(subRootDir, false, false, log) + + subStoreMap := make(map[string]*storage.ImageStore) + + subStoreMap["/b"] = subStore + + storeController := storage.StoreController{DefaultStore: defaultStore, SubStore: subStoreMap} + + dir := common.GetRootDir("a/zot-cve-test", storeController) + + So(dir, ShouldEqual, rootDir) + + dir = common.GetRootDir("b/zot-cve-test", storeController) + + So(dir, ShouldEqual, subRootDir) + }) +} diff --git a/pkg/extensions/search/common/oci_layout.go b/pkg/extensions/search/common/oci_layout.go index 123853b6..89074cb3 100644 --- a/pkg/extensions/search/common/oci_layout.go +++ b/pkg/extensions/search/common/oci_layout.go @@ -3,52 +3,31 @@ package common import ( "encoding/json" - "fmt" "io/ioutil" "os" "path" "strings" + "time" "github.com/anuvu/zot/errors" "github.com/anuvu/zot/pkg/log" - "github.com/anuvu/zot/pkg/storage" v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/types" godigest "github.com/opencontainers/go-digest" ispec "github.com/opencontainers/image-spec/specs-go/v1" ) -// CveInfo ... +// OciLayoutInfo ... type OciLayoutUtils struct { - Log log.Logger - StoreController storage.StoreController + Log log.Logger } // NewOciLayoutUtils initializes a new OciLayoutUtils object. -func NewOciLayoutUtils(storeController storage.StoreController, log log.Logger) *OciLayoutUtils { - return &OciLayoutUtils{Log: log, StoreController: storeController} +func NewOciLayoutUtils(log log.Logger) *OciLayoutUtils { + return &OciLayoutUtils{Log: log} } // Below method will return image path including root dir, root dir is determined by splitting. -func (olu OciLayoutUtils) GetImageRepoPath(image string) string { - var rootDir string - - prefixName := GetRoutePrefix(image) - - subStore := olu.StoreController.SubStore - - if subStore != nil { - imgStore, ok := olu.StoreController.SubStore[prefixName] - if ok { - rootDir = imgStore.RootDir() - } else { - rootDir = olu.StoreController.DefaultStore.RootDir() - } - } else { - rootDir = olu.StoreController.DefaultStore.RootDir() - } - - return path.Join(rootDir, image) -} func (olu OciLayoutUtils) GetImageManifests(imagePath string) ([]ispec.Descriptor, error) { buf, err := ioutil.ReadFile(path.Join(imagePath, "index.json")) @@ -113,17 +92,93 @@ func (olu OciLayoutUtils) GetImageInfo(imageDir string, hash v1.Hash) (ispec.Ima return imageInfo, err } -func GetRoutePrefix(name string) string { - names := strings.SplitN(name, "/", 2) +func (olu OciLayoutUtils) IsValidImageFormat(imagePath string) (bool, error) { + imageDir, inputTag := GetImageDirAndTag(imagePath) - if len(names) != 2 { // nolint: gomnd - // it means route is of global storage e.g "centos:latest" - if len(names) == 1 { - return "/" + if !DirExists(imageDir) { + olu.Log.Error().Msg("image directory doesn't exist") + + return false, errors.ErrRepoNotFound + } + + manifests, err := olu.GetImageManifests(imageDir) + + if err != nil { + return false, err + } + + for _, m := range manifests { + tag, ok := m.Annotations[ispec.AnnotationRefName] + + if ok && inputTag != "" && tag != inputTag { + continue + } + + blobManifest, err := olu.GetImageBlobManifest(imageDir, m.Digest) + if err != nil { + return false, err + } + + imageLayers := blobManifest.Layers + + for _, imageLayer := range imageLayers { + switch imageLayer.MediaType { + case types.OCILayer, types.DockerLayer: + return true, nil + + default: + olu.Log.Debug().Msg("image media type not supported for scanning") + return false, errors.ErrScanNotSupported + } } } - return fmt.Sprintf("/%s", names[0]) + return false, nil +} + +// GetImageTagsWithTimestamp returns a list of image tags with timestamp available in the specified repository. +func (olu OciLayoutUtils) GetImageTagsWithTimestamp(repo string) ([]TagInfo, error) { + tagsInfo := make([]TagInfo, 0) + + manifests, err := olu.GetImageManifests(repo) + if err != nil { + olu.Log.Error().Err(err).Msg("unable to read image manifests") + + return tagsInfo, err + } + + for _, manifest := range manifests { + digest := manifest.Digest + + v, ok := manifest.Annotations[ispec.AnnotationRefName] + if ok { + imageBlobManifest, err := olu.GetImageBlobManifest(repo, digest) + if err != nil { + olu.Log.Error().Err(err).Msg("unable to read image blob manifest") + + return tagsInfo, err + } + + imageInfo, err := olu.GetImageInfo(repo, imageBlobManifest.Config.Digest) + if err != nil { + olu.Log.Error().Err(err).Msg("unable to read image info") + + return tagsInfo, err + } + + var timeStamp time.Time + + if len(imageInfo.History) != 0 { + timeStamp = *imageInfo.History[0].Created + } else { + timeStamp = time.Time{} + } + + tagsInfo = append(tagsInfo, TagInfo{Name: v, Timestamp: timeStamp, Digest: digest.String()}) + } + } + + return tagsInfo, nil } func DirExists(d string) bool { diff --git a/pkg/extensions/search/cve/cve.go b/pkg/extensions/search/cve/cve.go index b1bc2ca3..11c9f39c 100644 --- a/pkg/extensions/search/cve/cve.go +++ b/pkg/extensions/search/cve/cve.go @@ -3,18 +3,14 @@ package cveinfo import ( "fmt" "path" - "sort" "strings" - "github.com/anuvu/zot/errors" "github.com/anuvu/zot/pkg/extensions/search/common" "github.com/anuvu/zot/pkg/log" "github.com/anuvu/zot/pkg/storage" integration "github.com/aquasecurity/trivy/integration" config "github.com/aquasecurity/trivy/integration/config" "github.com/aquasecurity/trivy/pkg/report" - "github.com/google/go-containerregistry/pkg/v1/types" - ispec "github.com/opencontainers/image-spec/specs-go/v1" ) // UpdateCVEDb ... @@ -44,7 +40,7 @@ func ScanImage(config *config.Config) (report.Results, error) { func GetCVEInfo(storeController storage.StoreController, log log.Logger) (*CveInfo, error) { cveController := CveTrivyController{} - layoutUtils := common.NewOciLayoutUtils(storeController, log) + layoutUtils := common.NewOciLayoutUtils(log) subCveConfig := make(map[string]*config.Config) @@ -122,50 +118,6 @@ func (cveinfo CveInfo) GetTrivyConfig(image string) *config.Config { return trivyConfig } -func (cveinfo CveInfo) IsValidImageFormat(imagePath string) (bool, error) { - imageDir, inputTag := common.GetImageDirAndTag(imagePath) - - if !common.DirExists(imageDir) { - cveinfo.Log.Error().Msg("image directory doesn't exist") - - return false, errors.ErrRepoNotFound - } - - manifests, err := cveinfo.LayoutUtils.GetImageManifests(imageDir) - - if err != nil { - return false, err - } - - for _, m := range manifests { - tag, ok := m.Annotations[ispec.AnnotationRefName] - - if ok && inputTag != "" && tag != inputTag { - continue - } - - blobManifest, err := cveinfo.LayoutUtils.GetImageBlobManifest(imageDir, m.Digest) - if err != nil { - return false, err - } - - imageLayers := blobManifest.Layers - - for _, imageLayer := range imageLayers { - switch imageLayer.MediaType { - case types.OCILayer, types.DockerLayer: - return true, nil - - default: - cveinfo.Log.Debug().Msg("image media type not supported for scanning") - return false, errors.ErrScanNotSupported - } - } - } - - return false, nil -} - func (cveinfo CveInfo) GetImageListForCVE(repo string, id string, imgStore *storage.ImageStore, trivyConfig *config.Config) ([]*string, error) { tags := make([]*string, 0) @@ -182,7 +134,7 @@ func (cveinfo CveInfo) GetImageListForCVE(repo string, id string, imgStore *stor for _, tag := range tagList { trivyConfig.TrivyConfig.Input = fmt.Sprintf("%s:%s", path.Join(rootDir, repo), tag) - isValidImage, _ := cveinfo.IsValidImageFormat(trivyConfig.TrivyConfig.Input) + isValidImage, _ := cveinfo.LayoutUtils.IsValidImageFormat(trivyConfig.TrivyConfig.Input) if !isValidImage { cveinfo.Log.Debug().Str("image", repo+":"+tag).Msg("image media type not supported for scanning") @@ -212,73 +164,3 @@ func (cveinfo CveInfo) GetImageListForCVE(repo string, id string, imgStore *stor return tags, nil } - -// GetImageTagsWithTimestamp returns a list of image tags with timestamp available in the specified repository. -func (cveinfo CveInfo) GetImageTagsWithTimestamp(repo string) ([]TagInfo, error) { - tagsInfo := make([]TagInfo, 0) - - imagePath := cveinfo.LayoutUtils.GetImageRepoPath(repo) - if !common.DirExists(imagePath) { - return nil, errors.ErrRepoNotFound - } - - manifests, err := cveinfo.LayoutUtils.GetImageManifests(imagePath) - - if err != nil { - cveinfo.Log.Error().Err(err).Msg("unable to read image manifests") - - return tagsInfo, err - } - - for _, manifest := range manifests { - digest := manifest.Digest - - v, ok := manifest.Annotations[ispec.AnnotationRefName] - if ok { - imageBlobManifest, err := cveinfo.LayoutUtils.GetImageBlobManifest(imagePath, digest) - - if err != nil { - cveinfo.Log.Error().Err(err).Msg("unable to read image blob manifest") - - return tagsInfo, err - } - - imageInfo, err := cveinfo.LayoutUtils.GetImageInfo(imagePath, imageBlobManifest.Config.Digest) - if err != nil { - cveinfo.Log.Error().Err(err).Msg("unable to read image info") - - return tagsInfo, err - } - - timeStamp := *imageInfo.History[0].Created - - tagsInfo = append(tagsInfo, TagInfo{Name: v, Timestamp: timeStamp}) - } - } - - return tagsInfo, nil -} - -func GetFixedTags(allTags []TagInfo, infectedTags []TagInfo) []TagInfo { - sort.Slice(allTags, func(i, j int) bool { - return allTags[i].Timestamp.Before(allTags[j].Timestamp) - }) - - latestInfected := TagInfo{} - - for _, tag := range infectedTags { - if !tag.Timestamp.Before(latestInfected.Timestamp) { - latestInfected = tag - } - } - - var fixedTags []TagInfo - - for _, tag := range allTags { - if tag.Timestamp.After(latestInfected.Timestamp) { - fixedTags = append(fixedTags, tag) - } - } - - return fixedTags -} diff --git a/pkg/extensions/search/cve/cve_test.go b/pkg/extensions/search/cve/cve_test.go index 66a7d21b..35249d30 100644 --- a/pkg/extensions/search/cve/cve_test.go +++ b/pkg/extensions/search/cve/cve_test.go @@ -95,7 +95,8 @@ func testSetup() error { log := log.NewLogger("debug", "") storeController := storage.StoreController{DefaultStore: storage.NewImageStore(dir, false, false, log)} - layoutUtils := common.NewOciLayoutUtils(storeController, log) + + layoutUtils := common.NewOciLayoutUtils(log) cve = &cveinfo.CveInfo{Log: log, StoreController: storeController, LayoutUtils: layoutUtils} @@ -116,30 +117,30 @@ func testSetup() error { func generateTestData() error { // nolint: gocyclo // Image dir with no files - err := os.Mkdir(path.Join(dbDir, "zot-noindex-test"), 0755) + err := os.Mkdir(path.Join(dbDir, "zot-noindex-test"), 0o755) if err != nil { return err } - err = os.Mkdir(path.Join(dbDir, "zot-nonreadable-test"), 0755) + err = os.Mkdir(path.Join(dbDir, "zot-nonreadable-test"), 0o755) if err != nil { return err } index := ispec.Index{} index.SchemaVersion = 2 - buf, err := json.Marshal(index) + buf, err := json.Marshal(index) if err != nil { return err } - if err = ioutil.WriteFile(path.Join(dbDir, "zot-nonreadable-test", "index.json"), buf, 0111); err != nil { + if err = ioutil.WriteFile(path.Join(dbDir, "zot-nonreadable-test", "index.json"), buf, 0o111); err != nil { return err } // Image dir with invalid index.json - err = os.Mkdir(path.Join(dbDir, "zot-squashfs-invalid-index"), 0755) + err = os.Mkdir(path.Join(dbDir, "zot-squashfs-invalid-index"), 0o755) if err != nil { return err } @@ -152,7 +153,7 @@ func generateTestData() error { // nolint: gocyclo } // Image dir with no blobs - err = os.Mkdir(path.Join(dbDir, "zot-squashfs-noblobs"), 0755) + err = os.Mkdir(path.Join(dbDir, "zot-squashfs-noblobs"), 0o755) if err != nil { return err } @@ -166,7 +167,7 @@ func generateTestData() error { // nolint: gocyclo } // Image dir with invalid blob - err = os.MkdirAll(path.Join(dbDir, "zot-squashfs-invalid-blob", "blobs/sha256"), 0755) + err = os.MkdirAll(path.Join(dbDir, "zot-squashfs-invalid-blob", "blobs/sha256"), 0o755) if err != nil { return err } @@ -189,7 +190,7 @@ func generateTestData() error { // nolint: gocyclo // Create a squashfs image - err = os.MkdirAll(path.Join(dbDir, "zot-squashfs-test", "blobs/sha256"), 0755) + err = os.MkdirAll(path.Join(dbDir, "zot-squashfs-test", "blobs/sha256"), 0o755) if err != nil { return err } @@ -201,11 +202,11 @@ func generateTestData() error { // nolint: gocyclo return err } - if err = ioutil.WriteFile(path.Join(dbDir, "zot-squashfs-test", "oci-layout"), buf, 0644); err != nil { //nolint: gosec + if err = ioutil.WriteFile(path.Join(dbDir, "zot-squashfs-test", "oci-layout"), buf, 0o644); err != nil { //nolint: gosec return err } - err = os.Mkdir(path.Join(dbDir, "zot-squashfs-test", ".uploads"), 0755) + err = os.Mkdir(path.Join(dbDir, "zot-squashfs-test", ".uploads"), 0o755) if err != nil { return err } @@ -261,7 +262,7 @@ func generateTestData() error { // nolint: gocyclo // Create a image with invalid layer blob - err = os.MkdirAll(path.Join(dbDir, "zot-invalid-layer", "blobs/sha256"), 0755) + err = os.MkdirAll(path.Join(dbDir, "zot-invalid-layer", "blobs/sha256"), 0o755) if err != nil { return err } @@ -289,7 +290,7 @@ func generateTestData() error { // nolint: gocyclo // Create a image with no layer blob - err = os.MkdirAll(path.Join(dbDir, "zot-no-layer", "blobs/sha256"), 0755) + err = os.MkdirAll(path.Join(dbDir, "zot-no-layer", "blobs/sha256"), 0o755) if err != nil { return err } @@ -319,7 +320,7 @@ func generateTestData() error { // nolint: gocyclo } func makeTestFile(fileName string, content string) error { - if err := ioutil.WriteFile(fileName, []byte(content), 0600); err != nil { + if err := ioutil.WriteFile(fileName, []byte(content), 0o600); err != nil { panic(err) } @@ -379,7 +380,7 @@ func makeHtpasswdFile() string { // bcrypt(username="test", passwd="test") content := []byte("test:$2y$05$hlbSXDp6hzDLu6VwACS39ORvVRpr3OMR4RlJ31jtlaOEGnPjKZI1m\n") - if err := ioutil.WriteFile(f.Name(), content, 0600); err != nil { + if err := ioutil.WriteFile(f.Name(), content, 0o600); err != nil { panic(err) } @@ -432,18 +433,6 @@ func TestMultipleStoragePath(t *testing.T) { So(err, ShouldBeNil) So(cveInfo.StoreController.DefaultStore, ShouldNotBeNil) So(cveInfo.StoreController.SubStore, ShouldNotBeNil) - - imagePath := cveInfo.LayoutUtils.GetImageRepoPath("zot-test") - So(imagePath, ShouldEqual, path.Join(firstRootDir, "zot-test")) - - imagePath = cveInfo.LayoutUtils.GetImageRepoPath("a/zot-a-test") - So(imagePath, ShouldEqual, path.Join(secondRootDir, "a/zot-a-test")) - - imagePath = cveInfo.LayoutUtils.GetImageRepoPath("b/zot-b-test") - So(imagePath, ShouldEqual, path.Join(thirdRootDir, "b/zot-b-test")) - - imagePath = cveInfo.LayoutUtils.GetImageRepoPath("c/zot-c-test") - So(imagePath, ShouldEqual, path.Join(firstRootDir, "c/zot-c-test")) }) } @@ -457,90 +446,6 @@ func TestDownloadDB(t *testing.T) { }) } -func TestImageFormat(t *testing.T) { - Convey("Test valid image", t, func() { - isValidImage, err := cve.IsValidImageFormat(path.Join(dbDir, "zot-test")) - So(err, ShouldBeNil) - So(isValidImage, ShouldEqual, true) - - isValidImage, err = cve.IsValidImageFormat(path.Join(dbDir, "zot-test:0.0.1")) - So(err, ShouldBeNil) - So(isValidImage, ShouldEqual, true) - - isValidImage, err = cve.IsValidImageFormat(path.Join(dbDir, "zot-test:0.0.")) - So(err, ShouldBeNil) - So(isValidImage, ShouldEqual, false) - - isValidImage, err = cve.IsValidImageFormat(path.Join(dbDir, "zot-noindex-test")) - So(err, ShouldNotBeNil) - So(isValidImage, ShouldEqual, false) - - isValidImage, err = cve.IsValidImageFormat(path.Join(dbDir, "zot--tet")) - So(err, ShouldNotBeNil) - So(isValidImage, ShouldEqual, false) - - isValidImage, err = cve.IsValidImageFormat(path.Join(dbDir, "zot-noindex-test")) - So(err, ShouldNotBeNil) - So(isValidImage, ShouldEqual, false) - - isValidImage, err = cve.IsValidImageFormat(path.Join(dbDir, "zot-squashfs-noblobs")) - So(err, ShouldNotBeNil) - So(isValidImage, ShouldEqual, false) - - isValidImage, err = cve.IsValidImageFormat(path.Join(dbDir, "zot-squashfs-invalid-index")) - So(err, ShouldNotBeNil) - So(isValidImage, ShouldEqual, false) - - isValidImage, err = cve.IsValidImageFormat(path.Join(dbDir, "zot-squashfs-invalid-blob")) - So(err, ShouldNotBeNil) - So(isValidImage, ShouldEqual, false) - - isValidImage, err = cve.IsValidImageFormat(path.Join(dbDir, "zot-squashfs-test:0.3.22-squashfs")) - So(err, ShouldNotBeNil) - So(isValidImage, ShouldEqual, false) - - isValidImage, err = cve.IsValidImageFormat(path.Join(dbDir, "zot-nonreadable-test")) - So(err, ShouldNotBeNil) - So(isValidImage, ShouldEqual, false) - }) -} - -func TestImageTag(t *testing.T) { - Convey("Test image tag", t, func() { - imageTags, err := cve.GetImageTagsWithTimestamp("zot-test") - So(err, ShouldBeNil) - So(len(imageTags), ShouldNotEqual, 0) - - imageTags, err = cve.GetImageTagsWithTimestamp("zot-tes") - So(err, ShouldNotBeNil) - So(imageTags, ShouldBeNil) - - imageTags, err = cve.GetImageTagsWithTimestamp("zot-noindex-test") - So(err, ShouldNotBeNil) - So(len(imageTags), ShouldEqual, 0) - - imageTags, err = cve.GetImageTagsWithTimestamp("zot-squashfs-noblobs") - So(err, ShouldNotBeNil) - So(len(imageTags), ShouldEqual, 0) - - imageTags, err = cve.GetImageTagsWithTimestamp("zot-squashfs-invalid-index") - So(err, ShouldNotBeNil) - So(len(imageTags), ShouldEqual, 0) - - imageTags, err = cve.GetImageTagsWithTimestamp("zot-squashfs-invalid-blob") - So(err, ShouldNotBeNil) - So(len(imageTags), ShouldEqual, 0) - - imageTags, err = cve.GetImageTagsWithTimestamp("zot-invalid-layer") - So(err, ShouldNotBeNil) - So(len(imageTags), ShouldEqual, 0) - - imageTags, err = cve.GetImageTagsWithTimestamp("zot-no-layer") - So(err, ShouldNotBeNil) - So(len(imageTags), ShouldEqual, 0) - }) -} - func TestCVESearch(t *testing.T) { Convey("Test image vulenrability scanning", t, func() { updateDuration, _ = time.ParseDuration("1h") diff --git a/pkg/extensions/search/cve/models.go b/pkg/extensions/search/cve/models.go index cd3733ac..60352598 100644 --- a/pkg/extensions/search/cve/models.go +++ b/pkg/extensions/search/cve/models.go @@ -2,8 +2,6 @@ package cveinfo import ( - "time" - "github.com/anuvu/zot/pkg/extensions/search/common" "github.com/anuvu/zot/pkg/log" "github.com/anuvu/zot/pkg/storage" @@ -22,8 +20,3 @@ type CveTrivyController struct { DefaultCveConfig *config.Config SubCveConfig map[string]*config.Config } - -type TagInfo struct { - Name string - Timestamp time.Time -} diff --git a/pkg/extensions/search/digest/digest.go b/pkg/extensions/search/digest/digest.go index 16ad10d1..523bfc6b 100644 --- a/pkg/extensions/search/digest/digest.go +++ b/pkg/extensions/search/digest/digest.go @@ -6,7 +6,6 @@ import ( "github.com/anuvu/zot/errors" "github.com/anuvu/zot/pkg/extensions/search/common" "github.com/anuvu/zot/pkg/log" - "github.com/anuvu/zot/pkg/storage" ispec "github.com/opencontainers/image-spec/specs-go/v1" ) @@ -17,8 +16,8 @@ type DigestInfo struct { } // NewDigestInfo initializes a new DigestInfo object. -func NewDigestInfo(storeController storage.StoreController, log log.Logger) *DigestInfo { - layoutUtils := common.NewOciLayoutUtils(storeController, log) +func NewDigestInfo(log log.Logger) *DigestInfo { + layoutUtils := common.NewOciLayoutUtils(log) return &DigestInfo{Log: log, LayoutUtils: layoutUtils} } @@ -27,12 +26,11 @@ func NewDigestInfo(storeController storage.StoreController, log log.Logger) *Dig func (digestinfo DigestInfo) GetImageTagsByDigest(repo string, digest string) ([]*string, error) { uniqueTags := []*string{} - imagePath := digestinfo.LayoutUtils.GetImageRepoPath(repo) - if !common.DirExists(imagePath) { + if !common.DirExists(repo) { return nil, errors.ErrRepoNotFound } - manifests, err := digestinfo.LayoutUtils.GetImageManifests(imagePath) + manifests, err := digestinfo.LayoutUtils.GetImageManifests(repo) if err != nil { digestinfo.Log.Error().Err(err).Msg("unable to read image manifests") @@ -44,7 +42,7 @@ func (digestinfo DigestInfo) GetImageTagsByDigest(repo string, digest string) ([ v, ok := manifest.Annotations[ispec.AnnotationRefName] if ok { - imageBlobManifest, err := digestinfo.LayoutUtils.GetImageBlobManifest(imagePath, imageDigest) + imageBlobManifest, err := digestinfo.LayoutUtils.GetImageBlobManifest(repo, imageDigest) if err != nil { digestinfo.Log.Error().Err(err).Msg("unable to read image blob manifest") diff --git a/pkg/extensions/search/digest/digest_test.go b/pkg/extensions/search/digest/digest_test.go index f9fc67be..5552b865 100644 --- a/pkg/extensions/search/digest/digest_test.go +++ b/pkg/extensions/search/digest/digest_test.go @@ -15,7 +15,6 @@ import ( ext "github.com/anuvu/zot/pkg/extensions" digestinfo "github.com/anuvu/zot/pkg/extensions/search/digest" "github.com/anuvu/zot/pkg/log" - "github.com/anuvu/zot/pkg/storage" . "github.com/smartystreets/goconvey/convey" "gopkg.in/resty.v1" ) @@ -79,9 +78,7 @@ func testSetup() error { log := log.NewLogger("debug", "") - storeController := storage.StoreController{DefaultStore: storage.NewImageStore(rootDir, false, false, log)} - - digestInfo = digestinfo.NewDigestInfo(storeController, log) + digestInfo = digestinfo.NewDigestInfo(log) return nil } @@ -134,30 +131,30 @@ func copyFiles(sourceDir string, destDir string) error { func TestDigestInfo(t *testing.T) { Convey("Test image tag", t, func() { // Search by manifest digest - imageTags, err := digestInfo.GetImageTagsByDigest("zot-cve-test", "63a795ca") + imageTags, err := digestInfo.GetImageTagsByDigest(path.Join(rootDir, "zot-cve-test"), "63a795ca") So(err, ShouldBeNil) So(len(imageTags), ShouldEqual, 1) So(*imageTags[0], ShouldEqual, "0.0.1") // Search by config digest - imageTags, err = digestInfo.GetImageTagsByDigest("zot-test", "adf3bb6c") + imageTags, err = digestInfo.GetImageTagsByDigest(path.Join(rootDir, "zot-test"), "adf3bb6c") So(err, ShouldBeNil) So(len(imageTags), ShouldEqual, 1) So(*imageTags[0], ShouldEqual, "0.0.1") // Search by layer digest - imageTags, err = digestInfo.GetImageTagsByDigest("zot-cve-test", "7a0437f0") + imageTags, err = digestInfo.GetImageTagsByDigest(path.Join(rootDir, "zot-cve-test"), "7a0437f0") So(err, ShouldBeNil) So(len(imageTags), ShouldEqual, 1) So(*imageTags[0], ShouldEqual, "0.0.1") // Search by non-existent image - imageTags, err = digestInfo.GetImageTagsByDigest("zot-tes", "63a795ca") + imageTags, err = digestInfo.GetImageTagsByDigest(path.Join(rootDir, "zot-tes"), "63a795ca") So(err, ShouldNotBeNil) So(len(imageTags), ShouldEqual, 0) // Search by non-existent digest - imageTags, err = digestInfo.GetImageTagsByDigest("zot-test", "111") + imageTags, err = digestInfo.GetImageTagsByDigest(path.Join(rootDir, "zot-test"), "111") So(err, ShouldBeNil) So(len(imageTags), ShouldEqual, 0) }) diff --git a/pkg/extensions/search/generated.go b/pkg/extensions/search/generated.go index 92838ddb..add3261a 100644 --- a/pkg/extensions/search/generated.go +++ b/pkg/extensions/search/generated.go @@ -57,6 +57,17 @@ type ComplexityRoot struct { Tag func(childComplexity int) int } + ImageInfo struct { + Description func(childComplexity int) int + Labels func(childComplexity int) int + LastUpdated func(childComplexity int) int + Latest func(childComplexity int) int + Licenses func(childComplexity int) int + Name func(childComplexity int) int + Size func(childComplexity int) int + Vendor func(childComplexity int) int + } + ImgResultForCve struct { Name func(childComplexity int) int Tags func(childComplexity int) int @@ -78,13 +89,15 @@ type ComplexityRoot struct { } Query struct { - CVEListForImage func(childComplexity int, image string) int - ImageListForCve func(childComplexity int, id string) int - ImageListForDigest func(childComplexity int, id string) int - ImageListWithCVEFixed func(childComplexity int, id string, image string) int + CVEListForImage func(childComplexity int, image string) int + ImageListForCve func(childComplexity int, id string) int + ImageListForDigest func(childComplexity int, id string) int + ImageListWithCVEFixed func(childComplexity int, id string, image string) int + ImageListWithLatestTag func(childComplexity int) int } TagInfo struct { + Digest func(childComplexity int) int Name func(childComplexity int) int Timestamp func(childComplexity int) int } @@ -95,6 +108,7 @@ type QueryResolver interface { ImageListForCve(ctx context.Context, id string) ([]*ImgResultForCve, error) ImageListWithCVEFixed(ctx context.Context, id string, image string) (*ImgResultForFixedCve, error) ImageListForDigest(ctx context.Context, id string) ([]*ImgResultForDigest, error) + ImageListWithLatestTag(ctx context.Context) ([]*ImageInfo, error) } type executableSchema struct { @@ -161,6 +175,62 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.CVEResultForImage.Tag(childComplexity), true + case "ImageInfo.Description": + if e.complexity.ImageInfo.Description == nil { + break + } + + return e.complexity.ImageInfo.Description(childComplexity), true + + case "ImageInfo.Labels": + if e.complexity.ImageInfo.Labels == nil { + break + } + + return e.complexity.ImageInfo.Labels(childComplexity), true + + case "ImageInfo.LastUpdated": + if e.complexity.ImageInfo.LastUpdated == nil { + break + } + + return e.complexity.ImageInfo.LastUpdated(childComplexity), true + + case "ImageInfo.Latest": + if e.complexity.ImageInfo.Latest == nil { + break + } + + return e.complexity.ImageInfo.Latest(childComplexity), true + + case "ImageInfo.Licenses": + if e.complexity.ImageInfo.Licenses == nil { + break + } + + return e.complexity.ImageInfo.Licenses(childComplexity), true + + case "ImageInfo.Name": + if e.complexity.ImageInfo.Name == nil { + break + } + + return e.complexity.ImageInfo.Name(childComplexity), true + + case "ImageInfo.Size": + if e.complexity.ImageInfo.Size == nil { + break + } + + return e.complexity.ImageInfo.Size(childComplexity), true + + case "ImageInfo.Vendor": + if e.complexity.ImageInfo.Vendor == nil { + break + } + + return e.complexity.ImageInfo.Vendor(childComplexity), true + case "ImgResultForCVE.Name": if e.complexity.ImgResultForCve.Name == nil { break @@ -265,6 +335,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Query.ImageListWithCVEFixed(childComplexity, args["id"].(string), args["image"].(string)), true + case "Query.ImageListWithLatestTag": + if e.complexity.Query.ImageListWithLatestTag == nil { + break + } + + return e.complexity.Query.ImageListWithLatestTag(childComplexity), true + + case "TagInfo.Digest": + if e.complexity.TagInfo.Digest == nil { + break + } + + return e.complexity.TagInfo.Digest(childComplexity), true + case "TagInfo.Name": if e.complexity.TagInfo.Name == nil { break @@ -366,15 +450,29 @@ type ImgResultForDigest { type TagInfo { Name: String + Digest: String Timestamp: Time } +type ImageInfo { + Name: String + Latest: String + LastUpdated: Time + Description: String + Licenses: String + Vendor: String + Size: String + Labels: String +} + type Query { CVEListForImage(image: String!) :CVEResultForImage ImageListForCVE(id: String!) :[ImgResultForCVE] ImageListWithCVEFixed(id: String!, image: String!) :ImgResultForFixedCVE ImageListForDigest(id: String!) :[ImgResultForDigest] -}`, BuiltIn: false}, + ImageListWithLatestTag:[ImageInfo] +} +`, BuiltIn: false}, } var parsedSchema = gqlparser.MustLoadSchema(sources...) @@ -387,7 +485,7 @@ func (ec *executionContext) dir_deprecated_args(ctx context.Context, rawArgs map args := map[string]interface{}{} var arg0 *string if tmp, ok := rawArgs["reason"]; ok { - ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("reason")) + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("reason")) arg0, err = ec.unmarshalOString2ᚖstring(ctx, tmp) if err != nil { return nil, err @@ -402,7 +500,7 @@ func (ec *executionContext) dir_include_args(ctx context.Context, rawArgs map[st args := map[string]interface{}{} var arg0 bool if tmp, ok := rawArgs["if"]; ok { - ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("if")) + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("if")) arg0, err = ec.unmarshalNBoolean2bool(ctx, tmp) if err != nil { return nil, err @@ -417,7 +515,7 @@ func (ec *executionContext) dir_skip_args(ctx context.Context, rawArgs map[strin args := map[string]interface{}{} var arg0 bool if tmp, ok := rawArgs["if"]; ok { - ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("if")) + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("if")) arg0, err = ec.unmarshalNBoolean2bool(ctx, tmp) if err != nil { return nil, err @@ -432,7 +530,7 @@ func (ec *executionContext) field_Query_CVEListForImage_args(ctx context.Context args := map[string]interface{}{} var arg0 string if tmp, ok := rawArgs["image"]; ok { - ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("image")) + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("image")) arg0, err = ec.unmarshalNString2string(ctx, tmp) if err != nil { return nil, err @@ -447,7 +545,7 @@ func (ec *executionContext) field_Query_ImageListForCVE_args(ctx context.Context args := map[string]interface{}{} var arg0 string if tmp, ok := rawArgs["id"]; ok { - ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("id")) + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) arg0, err = ec.unmarshalNString2string(ctx, tmp) if err != nil { return nil, err @@ -462,7 +560,7 @@ func (ec *executionContext) field_Query_ImageListForDigest_args(ctx context.Cont args := map[string]interface{}{} var arg0 string if tmp, ok := rawArgs["id"]; ok { - ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("id")) + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) arg0, err = ec.unmarshalNString2string(ctx, tmp) if err != nil { return nil, err @@ -477,7 +575,7 @@ func (ec *executionContext) field_Query_ImageListWithCVEFixed_args(ctx context.C args := map[string]interface{}{} var arg0 string if tmp, ok := rawArgs["id"]; ok { - ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("id")) + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) arg0, err = ec.unmarshalNString2string(ctx, tmp) if err != nil { return nil, err @@ -486,7 +584,7 @@ func (ec *executionContext) field_Query_ImageListWithCVEFixed_args(ctx context.C args["id"] = arg0 var arg1 string if tmp, ok := rawArgs["image"]; ok { - ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("image")) + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("image")) arg1, err = ec.unmarshalNString2string(ctx, tmp) if err != nil { return nil, err @@ -501,7 +599,7 @@ func (ec *executionContext) field_Query___type_args(ctx context.Context, rawArgs args := map[string]interface{}{} var arg0 string if tmp, ok := rawArgs["name"]; ok { - ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("name")) + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) arg0, err = ec.unmarshalNString2string(ctx, tmp) if err != nil { return nil, err @@ -516,7 +614,7 @@ func (ec *executionContext) field___Type_enumValues_args(ctx context.Context, ra args := map[string]interface{}{} var arg0 bool if tmp, ok := rawArgs["includeDeprecated"]; ok { - ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("includeDeprecated")) + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDeprecated")) arg0, err = ec.unmarshalOBoolean2bool(ctx, tmp) if err != nil { return nil, err @@ -531,7 +629,7 @@ func (ec *executionContext) field___Type_fields_args(ctx context.Context, rawArg args := map[string]interface{}{} var arg0 bool if tmp, ok := rawArgs["includeDeprecated"]; ok { - ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("includeDeprecated")) + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDeprecated")) arg0, err = ec.unmarshalOBoolean2bool(ctx, tmp) if err != nil { return nil, err @@ -599,10 +697,11 @@ func (ec *executionContext) _CVE_Id(ctx context.Context, field graphql.Collected } }() fc := &graphql.FieldContext{ - Object: "CVE", - Field: field, - Args: nil, - IsMethod: false, + Object: "CVE", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -627,10 +726,11 @@ func (ec *executionContext) _CVE_Title(ctx context.Context, field graphql.Collec } }() fc := &graphql.FieldContext{ - Object: "CVE", - Field: field, - Args: nil, - IsMethod: false, + Object: "CVE", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -655,10 +755,11 @@ func (ec *executionContext) _CVE_Description(ctx context.Context, field graphql. } }() fc := &graphql.FieldContext{ - Object: "CVE", - Field: field, - Args: nil, - IsMethod: false, + Object: "CVE", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -683,10 +784,11 @@ func (ec *executionContext) _CVE_Severity(ctx context.Context, field graphql.Col } }() fc := &graphql.FieldContext{ - Object: "CVE", - Field: field, - Args: nil, - IsMethod: false, + Object: "CVE", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -711,10 +813,11 @@ func (ec *executionContext) _CVE_PackageList(ctx context.Context, field graphql. } }() fc := &graphql.FieldContext{ - Object: "CVE", - Field: field, - Args: nil, - IsMethod: false, + Object: "CVE", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -739,10 +842,11 @@ func (ec *executionContext) _CVEResultForImage_Tag(ctx context.Context, field gr } }() fc := &graphql.FieldContext{ - Object: "CVEResultForImage", - Field: field, - Args: nil, - IsMethod: false, + Object: "CVEResultForImage", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -767,10 +871,11 @@ func (ec *executionContext) _CVEResultForImage_CVEList(ctx context.Context, fiel } }() fc := &graphql.FieldContext{ - Object: "CVEResultForImage", - Field: field, - Args: nil, - IsMethod: false, + Object: "CVEResultForImage", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -787,6 +892,238 @@ func (ec *executionContext) _CVEResultForImage_CVEList(ctx context.Context, fiel return ec.marshalOCVE2ᚕᚖgithubᚗcomᚋanuvuᚋzotᚋpkgᚋextensionsᚋsearchᚐCve(ctx, field.Selections, res) } +func (ec *executionContext) _ImageInfo_Name(ctx context.Context, field graphql.CollectedField, obj *ImageInfo) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ImageInfo", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _ImageInfo_Latest(ctx context.Context, field graphql.CollectedField, obj *ImageInfo) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ImageInfo", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Latest, nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _ImageInfo_LastUpdated(ctx context.Context, field graphql.CollectedField, obj *ImageInfo) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ImageInfo", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.LastUpdated, nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*time.Time) + fc.Result = res + return ec.marshalOTime2ᚖtimeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) _ImageInfo_Description(ctx context.Context, field graphql.CollectedField, obj *ImageInfo) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ImageInfo", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Description, nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _ImageInfo_Licenses(ctx context.Context, field graphql.CollectedField, obj *ImageInfo) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ImageInfo", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Licenses, nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _ImageInfo_Vendor(ctx context.Context, field graphql.CollectedField, obj *ImageInfo) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ImageInfo", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Vendor, nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _ImageInfo_Size(ctx context.Context, field graphql.CollectedField, obj *ImageInfo) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ImageInfo", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Size, nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _ImageInfo_Labels(ctx context.Context, field graphql.CollectedField, obj *ImageInfo) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ImageInfo", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Labels, nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + func (ec *executionContext) _ImgResultForCVE_Name(ctx context.Context, field graphql.CollectedField, obj *ImgResultForCve) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -795,10 +1132,11 @@ func (ec *executionContext) _ImgResultForCVE_Name(ctx context.Context, field gra } }() fc := &graphql.FieldContext{ - Object: "ImgResultForCVE", - Field: field, - Args: nil, - IsMethod: false, + Object: "ImgResultForCVE", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -823,10 +1161,11 @@ func (ec *executionContext) _ImgResultForCVE_Tags(ctx context.Context, field gra } }() fc := &graphql.FieldContext{ - Object: "ImgResultForCVE", - Field: field, - Args: nil, - IsMethod: false, + Object: "ImgResultForCVE", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -851,10 +1190,11 @@ func (ec *executionContext) _ImgResultForDigest_Name(ctx context.Context, field } }() fc := &graphql.FieldContext{ - Object: "ImgResultForDigest", - Field: field, - Args: nil, - IsMethod: false, + Object: "ImgResultForDigest", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -879,10 +1219,11 @@ func (ec *executionContext) _ImgResultForDigest_Tags(ctx context.Context, field } }() fc := &graphql.FieldContext{ - Object: "ImgResultForDigest", - Field: field, - Args: nil, - IsMethod: false, + Object: "ImgResultForDigest", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -907,10 +1248,11 @@ func (ec *executionContext) _ImgResultForFixedCVE_Tags(ctx context.Context, fiel } }() fc := &graphql.FieldContext{ - Object: "ImgResultForFixedCVE", - Field: field, - Args: nil, - IsMethod: false, + Object: "ImgResultForFixedCVE", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -935,10 +1277,11 @@ func (ec *executionContext) _PackageInfo_Name(ctx context.Context, field graphql } }() fc := &graphql.FieldContext{ - Object: "PackageInfo", - Field: field, - Args: nil, - IsMethod: false, + Object: "PackageInfo", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -963,10 +1306,11 @@ func (ec *executionContext) _PackageInfo_InstalledVersion(ctx context.Context, f } }() fc := &graphql.FieldContext{ - Object: "PackageInfo", - Field: field, - Args: nil, - IsMethod: false, + Object: "PackageInfo", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -991,10 +1335,11 @@ func (ec *executionContext) _PackageInfo_FixedVersion(ctx context.Context, field } }() fc := &graphql.FieldContext{ - Object: "PackageInfo", - Field: field, - Args: nil, - IsMethod: false, + Object: "PackageInfo", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -1019,10 +1364,11 @@ func (ec *executionContext) _Query_CVEListForImage(ctx context.Context, field gr } }() fc := &graphql.FieldContext{ - Object: "Query", - Field: field, - Args: nil, - IsMethod: true, + Object: "Query", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, } ctx = graphql.WithFieldContext(ctx, fc) @@ -1054,10 +1400,11 @@ func (ec *executionContext) _Query_ImageListForCVE(ctx context.Context, field gr } }() fc := &graphql.FieldContext{ - Object: "Query", - Field: field, - Args: nil, - IsMethod: true, + Object: "Query", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, } ctx = graphql.WithFieldContext(ctx, fc) @@ -1089,10 +1436,11 @@ func (ec *executionContext) _Query_ImageListWithCVEFixed(ctx context.Context, fi } }() fc := &graphql.FieldContext{ - Object: "Query", - Field: field, - Args: nil, - IsMethod: true, + Object: "Query", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, } ctx = graphql.WithFieldContext(ctx, fc) @@ -1124,10 +1472,11 @@ func (ec *executionContext) _Query_ImageListForDigest(ctx context.Context, field } }() fc := &graphql.FieldContext{ - Object: "Query", - Field: field, - Args: nil, - IsMethod: true, + Object: "Query", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, } ctx = graphql.WithFieldContext(ctx, fc) @@ -1151,6 +1500,35 @@ func (ec *executionContext) _Query_ImageListForDigest(ctx context.Context, field return ec.marshalOImgResultForDigest2ᚕᚖgithubᚗcomᚋanuvuᚋzotᚋpkgᚋextensionsᚋsearchᚐImgResultForDigest(ctx, field.Selections, res) } +func (ec *executionContext) _Query_ImageListWithLatestTag(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Query", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().ImageListWithLatestTag(rctx) + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]*ImageInfo) + fc.Result = res + return ec.marshalOImageInfo2ᚕᚖgithubᚗcomᚋanuvuᚋzotᚋpkgᚋextensionsᚋsearchᚐImageInfo(ctx, field.Selections, res) +} + func (ec *executionContext) _Query___type(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -1159,10 +1537,11 @@ func (ec *executionContext) _Query___type(ctx context.Context, field graphql.Col } }() fc := &graphql.FieldContext{ - Object: "Query", - Field: field, - Args: nil, - IsMethod: true, + Object: "Query", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -1194,10 +1573,11 @@ func (ec *executionContext) _Query___schema(ctx context.Context, field graphql.C } }() fc := &graphql.FieldContext{ - Object: "Query", - Field: field, - Args: nil, - IsMethod: true, + Object: "Query", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -1222,10 +1602,11 @@ func (ec *executionContext) _TagInfo_Name(ctx context.Context, field graphql.Col } }() fc := &graphql.FieldContext{ - Object: "TagInfo", - Field: field, - Args: nil, - IsMethod: false, + Object: "TagInfo", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -1242,6 +1623,35 @@ func (ec *executionContext) _TagInfo_Name(ctx context.Context, field graphql.Col return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } +func (ec *executionContext) _TagInfo_Digest(ctx context.Context, field graphql.CollectedField, obj *TagInfo) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "TagInfo", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Digest, nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + func (ec *executionContext) _TagInfo_Timestamp(ctx context.Context, field graphql.CollectedField, obj *TagInfo) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -1250,10 +1660,11 @@ func (ec *executionContext) _TagInfo_Timestamp(ctx context.Context, field graphq } }() fc := &graphql.FieldContext{ - Object: "TagInfo", - Field: field, - Args: nil, - IsMethod: false, + Object: "TagInfo", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -1278,10 +1689,11 @@ func (ec *executionContext) ___Directive_name(ctx context.Context, field graphql } }() fc := &graphql.FieldContext{ - Object: "__Directive", - Field: field, - Args: nil, - IsMethod: false, + Object: "__Directive", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -1309,10 +1721,11 @@ func (ec *executionContext) ___Directive_description(ctx context.Context, field } }() fc := &graphql.FieldContext{ - Object: "__Directive", - Field: field, - Args: nil, - IsMethod: false, + Object: "__Directive", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -1337,10 +1750,11 @@ func (ec *executionContext) ___Directive_locations(ctx context.Context, field gr } }() fc := &graphql.FieldContext{ - Object: "__Directive", - Field: field, - Args: nil, - IsMethod: false, + Object: "__Directive", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -1368,10 +1782,11 @@ func (ec *executionContext) ___Directive_args(ctx context.Context, field graphql } }() fc := &graphql.FieldContext{ - Object: "__Directive", - Field: field, - Args: nil, - IsMethod: false, + Object: "__Directive", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -1399,10 +1814,11 @@ func (ec *executionContext) ___EnumValue_name(ctx context.Context, field graphql } }() fc := &graphql.FieldContext{ - Object: "__EnumValue", - Field: field, - Args: nil, - IsMethod: false, + Object: "__EnumValue", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -1430,10 +1846,11 @@ func (ec *executionContext) ___EnumValue_description(ctx context.Context, field } }() fc := &graphql.FieldContext{ - Object: "__EnumValue", - Field: field, - Args: nil, - IsMethod: false, + Object: "__EnumValue", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -1458,10 +1875,11 @@ func (ec *executionContext) ___EnumValue_isDeprecated(ctx context.Context, field } }() fc := &graphql.FieldContext{ - Object: "__EnumValue", - Field: field, - Args: nil, - IsMethod: true, + Object: "__EnumValue", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -1489,10 +1907,11 @@ func (ec *executionContext) ___EnumValue_deprecationReason(ctx context.Context, } }() fc := &graphql.FieldContext{ - Object: "__EnumValue", - Field: field, - Args: nil, - IsMethod: true, + Object: "__EnumValue", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -1517,10 +1936,11 @@ func (ec *executionContext) ___Field_name(ctx context.Context, field graphql.Col } }() fc := &graphql.FieldContext{ - Object: "__Field", - Field: field, - Args: nil, - IsMethod: false, + Object: "__Field", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -1548,10 +1968,11 @@ func (ec *executionContext) ___Field_description(ctx context.Context, field grap } }() fc := &graphql.FieldContext{ - Object: "__Field", - Field: field, - Args: nil, - IsMethod: false, + Object: "__Field", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -1576,10 +1997,11 @@ func (ec *executionContext) ___Field_args(ctx context.Context, field graphql.Col } }() fc := &graphql.FieldContext{ - Object: "__Field", - Field: field, - Args: nil, - IsMethod: false, + Object: "__Field", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -1607,10 +2029,11 @@ func (ec *executionContext) ___Field_type(ctx context.Context, field graphql.Col } }() fc := &graphql.FieldContext{ - Object: "__Field", - Field: field, - Args: nil, - IsMethod: false, + Object: "__Field", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -1638,10 +2061,11 @@ func (ec *executionContext) ___Field_isDeprecated(ctx context.Context, field gra } }() fc := &graphql.FieldContext{ - Object: "__Field", - Field: field, - Args: nil, - IsMethod: true, + Object: "__Field", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -1669,10 +2093,11 @@ func (ec *executionContext) ___Field_deprecationReason(ctx context.Context, fiel } }() fc := &graphql.FieldContext{ - Object: "__Field", - Field: field, - Args: nil, - IsMethod: true, + Object: "__Field", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -1697,10 +2122,11 @@ func (ec *executionContext) ___InputValue_name(ctx context.Context, field graphq } }() fc := &graphql.FieldContext{ - Object: "__InputValue", - Field: field, - Args: nil, - IsMethod: false, + Object: "__InputValue", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -1728,10 +2154,11 @@ func (ec *executionContext) ___InputValue_description(ctx context.Context, field } }() fc := &graphql.FieldContext{ - Object: "__InputValue", - Field: field, - Args: nil, - IsMethod: false, + Object: "__InputValue", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -1756,10 +2183,11 @@ func (ec *executionContext) ___InputValue_type(ctx context.Context, field graphq } }() fc := &graphql.FieldContext{ - Object: "__InputValue", - Field: field, - Args: nil, - IsMethod: false, + Object: "__InputValue", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -1787,10 +2215,11 @@ func (ec *executionContext) ___InputValue_defaultValue(ctx context.Context, fiel } }() fc := &graphql.FieldContext{ - Object: "__InputValue", - Field: field, - Args: nil, - IsMethod: false, + Object: "__InputValue", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -1815,10 +2244,11 @@ func (ec *executionContext) ___Schema_types(ctx context.Context, field graphql.C } }() fc := &graphql.FieldContext{ - Object: "__Schema", - Field: field, - Args: nil, - IsMethod: true, + Object: "__Schema", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -1846,10 +2276,11 @@ func (ec *executionContext) ___Schema_queryType(ctx context.Context, field graph } }() fc := &graphql.FieldContext{ - Object: "__Schema", - Field: field, - Args: nil, - IsMethod: true, + Object: "__Schema", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -1877,10 +2308,11 @@ func (ec *executionContext) ___Schema_mutationType(ctx context.Context, field gr } }() fc := &graphql.FieldContext{ - Object: "__Schema", - Field: field, - Args: nil, - IsMethod: true, + Object: "__Schema", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -1905,10 +2337,11 @@ func (ec *executionContext) ___Schema_subscriptionType(ctx context.Context, fiel } }() fc := &graphql.FieldContext{ - Object: "__Schema", - Field: field, - Args: nil, - IsMethod: true, + Object: "__Schema", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -1933,10 +2366,11 @@ func (ec *executionContext) ___Schema_directives(ctx context.Context, field grap } }() fc := &graphql.FieldContext{ - Object: "__Schema", - Field: field, - Args: nil, - IsMethod: true, + Object: "__Schema", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -1964,10 +2398,11 @@ func (ec *executionContext) ___Type_kind(ctx context.Context, field graphql.Coll } }() fc := &graphql.FieldContext{ - Object: "__Type", - Field: field, - Args: nil, - IsMethod: true, + Object: "__Type", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -1995,10 +2430,11 @@ func (ec *executionContext) ___Type_name(ctx context.Context, field graphql.Coll } }() fc := &graphql.FieldContext{ - Object: "__Type", - Field: field, - Args: nil, - IsMethod: true, + Object: "__Type", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -2023,10 +2459,11 @@ func (ec *executionContext) ___Type_description(ctx context.Context, field graph } }() fc := &graphql.FieldContext{ - Object: "__Type", - Field: field, - Args: nil, - IsMethod: true, + Object: "__Type", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -2051,10 +2488,11 @@ func (ec *executionContext) ___Type_fields(ctx context.Context, field graphql.Co } }() fc := &graphql.FieldContext{ - Object: "__Type", - Field: field, - Args: nil, - IsMethod: true, + Object: "__Type", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -2086,10 +2524,11 @@ func (ec *executionContext) ___Type_interfaces(ctx context.Context, field graphq } }() fc := &graphql.FieldContext{ - Object: "__Type", - Field: field, - Args: nil, - IsMethod: true, + Object: "__Type", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -2114,10 +2553,11 @@ func (ec *executionContext) ___Type_possibleTypes(ctx context.Context, field gra } }() fc := &graphql.FieldContext{ - Object: "__Type", - Field: field, - Args: nil, - IsMethod: true, + Object: "__Type", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -2142,10 +2582,11 @@ func (ec *executionContext) ___Type_enumValues(ctx context.Context, field graphq } }() fc := &graphql.FieldContext{ - Object: "__Type", - Field: field, - Args: nil, - IsMethod: true, + Object: "__Type", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -2177,10 +2618,11 @@ func (ec *executionContext) ___Type_inputFields(ctx context.Context, field graph } }() fc := &graphql.FieldContext{ - Object: "__Type", - Field: field, - Args: nil, - IsMethod: true, + Object: "__Type", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -2205,10 +2647,11 @@ func (ec *executionContext) ___Type_ofType(ctx context.Context, field graphql.Co } }() fc := &graphql.FieldContext{ - Object: "__Type", - Field: field, - Args: nil, - IsMethod: true, + Object: "__Type", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, } ctx = graphql.WithFieldContext(ctx, fc) @@ -2295,6 +2738,44 @@ func (ec *executionContext) _CVEResultForImage(ctx context.Context, sel ast.Sele return out } +var imageInfoImplementors = []string{"ImageInfo"} + +func (ec *executionContext) _ImageInfo(ctx context.Context, sel ast.SelectionSet, obj *ImageInfo) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, imageInfoImplementors) + + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("ImageInfo") + case "Name": + out.Values[i] = ec._ImageInfo_Name(ctx, field, obj) + case "Latest": + out.Values[i] = ec._ImageInfo_Latest(ctx, field, obj) + case "LastUpdated": + out.Values[i] = ec._ImageInfo_LastUpdated(ctx, field, obj) + case "Description": + out.Values[i] = ec._ImageInfo_Description(ctx, field, obj) + case "Licenses": + out.Values[i] = ec._ImageInfo_Licenses(ctx, field, obj) + case "Vendor": + out.Values[i] = ec._ImageInfo_Vendor(ctx, field, obj) + case "Size": + out.Values[i] = ec._ImageInfo_Size(ctx, field, obj) + case "Labels": + out.Values[i] = ec._ImageInfo_Labels(ctx, field, obj) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + var imgResultForCVEImplementors = []string{"ImgResultForCVE"} func (ec *executionContext) _ImgResultForCVE(ctx context.Context, sel ast.SelectionSet, obj *ImgResultForCve) graphql.Marshaler { @@ -2458,6 +2939,17 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr res = ec._Query_ImageListForDigest(ctx, field) return res }) + case "ImageListWithLatestTag": + field := field + out.Concurrently(i, func() (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_ImageListWithLatestTag(ctx, field) + return res + }) case "__type": out.Values[i] = ec._Query___type(ctx, field) case "__schema": @@ -2486,6 +2978,8 @@ func (ec *executionContext) _TagInfo(ctx context.Context, sel ast.SelectionSet, out.Values[i] = graphql.MarshalString("TagInfo") case "Name": out.Values[i] = ec._TagInfo_Name(ctx, field, obj) + case "Digest": + out.Values[i] = ec._TagInfo_Digest(ctx, field, obj) case "Timestamp": out.Values[i] = ec._TagInfo_Timestamp(ctx, field, obj) default: @@ -2746,7 +3240,7 @@ func (ec *executionContext) ___Type(ctx context.Context, sel ast.SelectionSet, o func (ec *executionContext) unmarshalNBoolean2bool(ctx context.Context, v interface{}) (bool, error) { res, err := graphql.UnmarshalBoolean(v) - return res, graphql.WrapErrorWithInputPath(ctx, err) + return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNBoolean2bool(ctx context.Context, sel ast.SelectionSet, v bool) graphql.Marshaler { @@ -2761,7 +3255,7 @@ func (ec *executionContext) marshalNBoolean2bool(ctx context.Context, sel ast.Se func (ec *executionContext) unmarshalNString2string(ctx context.Context, v interface{}) (string, error) { res, err := graphql.UnmarshalString(v) - return res, graphql.WrapErrorWithInputPath(ctx, err) + return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNString2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { @@ -2817,7 +3311,7 @@ func (ec *executionContext) marshalN__Directive2ᚕgithubᚗcomᚋ99designsᚋgq func (ec *executionContext) unmarshalN__DirectiveLocation2string(ctx context.Context, v interface{}) (string, error) { res, err := graphql.UnmarshalString(v) - return res, graphql.WrapErrorWithInputPath(ctx, err) + return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalN__DirectiveLocation2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { @@ -2842,10 +3336,10 @@ func (ec *executionContext) unmarshalN__DirectiveLocation2ᚕstringᚄ(ctx conte var err error res := make([]string, len(vSlice)) for i := range vSlice { - ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithIndex(i)) + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) res[i], err = ec.unmarshalN__DirectiveLocation2string(ctx, vSlice[i]) if err != nil { - return nil, graphql.WrapErrorWithInputPath(ctx, err) + return nil, err } } return res, nil @@ -2990,7 +3484,7 @@ func (ec *executionContext) marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgen func (ec *executionContext) unmarshalN__TypeKind2string(ctx context.Context, v interface{}) (string, error) { res, err := graphql.UnmarshalString(v) - return res, graphql.WrapErrorWithInputPath(ctx, err) + return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalN__TypeKind2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { @@ -3005,7 +3499,7 @@ func (ec *executionContext) marshalN__TypeKind2string(ctx context.Context, sel a func (ec *executionContext) unmarshalOBoolean2bool(ctx context.Context, v interface{}) (bool, error) { res, err := graphql.UnmarshalBoolean(v) - return res, graphql.WrapErrorWithInputPath(ctx, err) + return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOBoolean2bool(ctx context.Context, sel ast.SelectionSet, v bool) graphql.Marshaler { @@ -3017,7 +3511,7 @@ func (ec *executionContext) unmarshalOBoolean2ᚖbool(ctx context.Context, v int return nil, nil } res, err := graphql.UnmarshalBoolean(v) - return &res, graphql.WrapErrorWithInputPath(ctx, err) + return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOBoolean2ᚖbool(ctx context.Context, sel ast.SelectionSet, v *bool) graphql.Marshaler { @@ -3081,6 +3575,53 @@ func (ec *executionContext) marshalOCVEResultForImage2ᚖgithubᚗcomᚋanuvuᚋ return ec._CVEResultForImage(ctx, sel, v) } +func (ec *executionContext) marshalOImageInfo2ᚕᚖgithubᚗcomᚋanuvuᚋzotᚋpkgᚋextensionsᚋsearchᚐImageInfo(ctx context.Context, sel ast.SelectionSet, v []*ImageInfo) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalOImageInfo2ᚖgithubᚗcomᚋanuvuᚋzotᚋpkgᚋextensionsᚋsearchᚐImageInfo(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + return ret +} + +func (ec *executionContext) marshalOImageInfo2ᚖgithubᚗcomᚋanuvuᚋzotᚋpkgᚋextensionsᚋsearchᚐImageInfo(ctx context.Context, sel ast.SelectionSet, v *ImageInfo) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._ImageInfo(ctx, sel, v) +} + func (ec *executionContext) marshalOImgResultForCVE2ᚕᚖgithubᚗcomᚋanuvuᚋzotᚋpkgᚋextensionsᚋsearchᚐImgResultForCve(ctx context.Context, sel ast.SelectionSet, v []*ImgResultForCve) graphql.Marshaler { if v == nil { return graphql.Null @@ -3231,7 +3772,7 @@ func (ec *executionContext) marshalOPackageInfo2ᚖgithubᚗcomᚋanuvuᚋzotᚋ func (ec *executionContext) unmarshalOString2string(ctx context.Context, v interface{}) (string, error) { res, err := graphql.UnmarshalString(v) - return res, graphql.WrapErrorWithInputPath(ctx, err) + return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOString2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { @@ -3253,10 +3794,10 @@ func (ec *executionContext) unmarshalOString2ᚕᚖstring(ctx context.Context, v var err error res := make([]*string, len(vSlice)) for i := range vSlice { - ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithIndex(i)) + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) res[i], err = ec.unmarshalOString2ᚖstring(ctx, vSlice[i]) if err != nil { - return nil, graphql.WrapErrorWithInputPath(ctx, err) + return nil, err } } return res, nil @@ -3279,7 +3820,7 @@ func (ec *executionContext) unmarshalOString2ᚖstring(ctx context.Context, v in return nil, nil } res, err := graphql.UnmarshalString(v) - return &res, graphql.WrapErrorWithInputPath(ctx, err) + return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOString2ᚖstring(ctx context.Context, sel ast.SelectionSet, v *string) graphql.Marshaler { @@ -3341,7 +3882,7 @@ func (ec *executionContext) unmarshalOTime2ᚖtimeᚐTime(ctx context.Context, v return nil, nil } res, err := graphql.UnmarshalTime(v) - return &res, graphql.WrapErrorWithInputPath(ctx, err) + return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOTime2ᚖtimeᚐTime(ctx context.Context, sel ast.SelectionSet, v *time.Time) graphql.Marshaler { diff --git a/pkg/extensions/search/models_gen.go b/pkg/extensions/search/models_gen.go index 54e2fdcd..38eb9e0f 100644 --- a/pkg/extensions/search/models_gen.go +++ b/pkg/extensions/search/models_gen.go @@ -19,6 +19,17 @@ type CVEResultForImage struct { CVEList []*Cve `json:"CVEList"` } +type ImageInfo struct { + Name *string `json:"Name"` + Latest *string `json:"Latest"` + LastUpdated *time.Time `json:"LastUpdated"` + Description *string `json:"Description"` + Licenses *string `json:"Licenses"` + Vendor *string `json:"Vendor"` + Size *string `json:"Size"` + Labels *string `json:"Labels"` +} + type ImgResultForCve struct { Name *string `json:"Name"` Tags []*string `json:"Tags"` @@ -41,5 +52,6 @@ type PackageInfo struct { type TagInfo struct { Name *string `json:"Name"` + Digest *string `json:"Digest"` Timestamp *time.Time `json:"Timestamp"` } diff --git a/pkg/extensions/search/resolver.go b/pkg/extensions/search/resolver.go index cf2fc360..857b0a3b 100644 --- a/pkg/extensions/search/resolver.go +++ b/pkg/extensions/search/resolver.go @@ -5,11 +5,15 @@ package search import ( "context" "fmt" + "path" + "strconv" "strings" "github.com/anuvu/zot/pkg/log" "github.com/aquasecurity/trivy/integration/config" + godigest "github.com/opencontainers/go-digest" + "github.com/anuvu/zot/pkg/extensions/search/common" cveinfo "github.com/anuvu/zot/pkg/extensions/search/cve" digestinfo "github.com/anuvu/zot/pkg/extensions/search/digest" "github.com/anuvu/zot/pkg/storage" @@ -20,6 +24,7 @@ type Resolver struct { cveInfo *cveinfo.CveInfo storeController storage.StoreController digestInfo *digestinfo.DigestInfo + log log.Logger } // Query ... @@ -37,34 +42,43 @@ type cveDetail struct { } // GetResolverConfig ... -func GetResolverConfig(log log.Logger, storeController storage.StoreController) Config { - cveInfo, err := cveinfo.GetCVEInfo(storeController, log) - if err != nil { - panic(err) +func GetResolverConfig(log log.Logger, storeController storage.StoreController, enableCVE bool) Config { + var cveInfo *cveinfo.CveInfo + + var err error + + if enableCVE { + cveInfo, err = cveinfo.GetCVEInfo(storeController, log) + if err != nil { + panic(err) + } } - digestInfo := digestinfo.NewDigestInfo(storeController, log) - resConfig := &Resolver{cveInfo: cveInfo, storeController: storeController, digestInfo: digestInfo} + digestInfo := digestinfo.NewDigestInfo(log) - return Config{Resolvers: resConfig, Directives: DirectiveRoot{}, - Complexity: ComplexityRoot{}} + resConfig := &Resolver{cveInfo: cveInfo, storeController: storeController, digestInfo: digestInfo, log: log} + + return Config{ + Resolvers: resConfig, Directives: DirectiveRoot{}, + Complexity: ComplexityRoot{}, + } } func (r *queryResolver) CVEListForImage(ctx context.Context, image string) (*CVEResultForImage, error) { trivyConfig := r.cveInfo.GetTrivyConfig(image) - r.cveInfo.Log.Info().Str("image", image).Msg("scanning image") + r.log.Info().Str("image", image).Msg("scanning image") - isValidImage, err := r.cveInfo.IsValidImageFormat(trivyConfig.TrivyConfig.Input) + isValidImage, err := r.cveInfo.LayoutUtils.IsValidImageFormat(trivyConfig.TrivyConfig.Input) if !isValidImage { - r.cveInfo.Log.Debug().Str("image", image).Msg("image media type not supported for scanning") + r.log.Debug().Str("image", image).Msg("image media type not supported for scanning") return &CVEResultForImage{}, err } cveResults, err := cveinfo.ScanImage(trivyConfig) if err != nil { - r.cveInfo.Log.Error().Err(err).Msg("unable to scan image repository") + r.log.Error().Err(err).Msg("unable to scan image repository") return &CVEResultForImage{}, err } @@ -108,8 +122,10 @@ func (r *queryResolver) CVEListForImage(ctx context.Context, image string) (*CVE newPkgList = append(newPkgList, &PackageInfo{Name: &pkgName, InstalledVersion: &installedVersion, FixedVersion: &fixedVersion}) - cveidMap[vulnerability.VulnerabilityID] = cveDetail{Title: vulnerability.Title, - Description: vulnerability.Description, Severity: vulnerability.Severity, PackageList: newPkgList} + cveidMap[vulnerability.VulnerabilityID] = cveDetail{ + Title: vulnerability.Title, + Description: vulnerability.Description, Severity: vulnerability.Severity, PackageList: newPkgList, + } } } } @@ -137,7 +153,7 @@ func (r *queryResolver) CVEListForImage(ctx context.Context, image string) (*CVE func (r *queryResolver) ImageListForCve(ctx context.Context, id string) ([]*ImgResultForCve, error) { finalCveResult := []*ImgResultForCve{} - r.cveInfo.Log.Info().Msg("extracting repositories") + r.log.Info().Msg("extracting repositories") defaultStore := r.storeController.DefaultStore @@ -145,7 +161,7 @@ func (r *queryResolver) ImageListForCve(ctx context.Context, id string) ([]*ImgR repoList, err := defaultStore.GetRepositories() if err != nil { - r.cveInfo.Log.Error().Err(err).Msg("unable to search repositories") + r.log.Error().Err(err).Msg("unable to search repositories") return finalCveResult, err } @@ -154,7 +170,7 @@ func (r *queryResolver) ImageListForCve(ctx context.Context, id string) ([]*ImgR cveResult, err := r.getImageListForCVE(repoList, id, defaultStore, defaultTrivyConfig) if err != nil { - r.cveInfo.Log.Error().Err(err).Msg("error getting cve list for global repositories") + r.log.Error().Err(err).Msg("error getting cve list for global repositories") return finalCveResult, err } @@ -165,7 +181,7 @@ func (r *queryResolver) ImageListForCve(ctx context.Context, id string) ([]*ImgR for route, store := range subStore { subRepoList, err := store.GetRepositories() if err != nil { - r.cveInfo.Log.Error().Err(err).Msg("unable to search repositories") + r.log.Error().Err(err).Msg("unable to search repositories") return cveResult, err } @@ -174,7 +190,7 @@ func (r *queryResolver) ImageListForCve(ctx context.Context, id string) ([]*ImgR subCveResult, err := r.getImageListForCVE(subRepoList, id, store, subTrivyConfig) if err != nil { - r.cveInfo.Log.Error().Err(err).Msg("unable to get cve result for sub repositories") + r.log.Error().Err(err).Msg("unable to get cve result for sub repositories") return finalCveResult, err } @@ -190,13 +206,13 @@ func (r *queryResolver) getImageListForCVE(repoList []string, id string, imgStor cveResult := []*ImgResultForCve{} for _, repo := range repoList { - r.cveInfo.Log.Info().Str("repo", repo).Msg("extracting list of tags available in image repo") + r.log.Info().Str("repo", repo).Msg("extracting list of tags available in image repo") name := repo tags, err := r.cveInfo.GetImageListForCVE(repo, id, imgStore, trivyConfig) if err != nil { - r.cveInfo.Log.Error().Err(err).Msg("error getting tag") + r.log.Error().Err(err).Msg("error getting tag") return cveResult, err } @@ -212,45 +228,47 @@ func (r *queryResolver) getImageListForCVE(repoList []string, id string, imgStor func (r *queryResolver) ImageListWithCVEFixed(ctx context.Context, id string, image string) (*ImgResultForFixedCve, error) { // nolint: lll imgResultForFixedCVE := &ImgResultForFixedCve{} - r.cveInfo.Log.Info().Str("image", image).Msg("retrieving image path") + r.log.Info().Str("image", image).Msg("retrieving image repo path") - imagePath := r.cveInfo.LayoutUtils.GetImageRepoPath(image) + imagePath := common.GetImageRepoPath(image, r.storeController) - r.cveInfo.Log.Info().Str("image", image).Msg("retrieving trivy config") + r.log.Info().Str("image", image).Msg("retrieving trivy config") trivyConfig := r.cveInfo.GetTrivyConfig(image) - r.cveInfo.Log.Info().Str("image", image).Msg("extracting list of tags available in image") + r.log.Info().Str("image", image).Msg("extracting list of tags available in image") - tagsInfo, err := r.cveInfo.GetImageTagsWithTimestamp(image) + tagsInfo, err := r.cveInfo.LayoutUtils.GetImageTagsWithTimestamp(imagePath) if err != nil { - r.cveInfo.Log.Error().Err(err).Msg("unable to read image tags") + r.log.Error().Err(err).Msg("unable to read image tags") return imgResultForFixedCVE, err } - infectedTags := make([]cveinfo.TagInfo, 0) + infectedTags := make([]common.TagInfo, 0) var hasCVE bool for _, tag := range tagsInfo { trivyConfig.TrivyConfig.Input = fmt.Sprintf("%s:%s", imagePath, tag.Name) - isValidImage, _ := r.cveInfo.IsValidImageFormat(trivyConfig.TrivyConfig.Input) + isValidImage, _ := r.cveInfo.LayoutUtils.IsValidImageFormat(trivyConfig.TrivyConfig.Input) if !isValidImage { - r.cveInfo.Log.Debug().Str("image", - image+":"+tag.Name).Msg("image media type not supported for scanning, adding as an infected image") + r.log.Debug().Str("image", + fmt.Sprintf("%s:%s", image, tag.Name)). + Msg("image media type not supported for scanning, adding as an infected image") - infectedTags = append(infectedTags, cveinfo.TagInfo{Name: tag.Name, Timestamp: tag.Timestamp}) + infectedTags = append(infectedTags, common.TagInfo{Name: tag.Name, Timestamp: tag.Timestamp}) continue } - r.cveInfo.Log.Info().Str("image", image+":"+tag.Name).Msg("scanning image") + r.cveInfo.Log.Info().Str("image", fmt.Sprintf("%s:%s", image, tag.Name)).Msg("scanning image") results, err := cveinfo.ScanImage(trivyConfig) if err != nil { - r.cveInfo.Log.Error().Err(err).Str("image", image+":"+tag.Name).Msg("unable to scan image") + r.log.Error().Err(err). + Str("image", fmt.Sprintf("%s:%s", image, tag.Name)).Msg("unable to scan image") continue } @@ -268,20 +286,20 @@ func (r *queryResolver) ImageListWithCVEFixed(ctx context.Context, id string, im } if hasCVE { - infectedTags = append(infectedTags, cveinfo.TagInfo{Name: tag.Name, Timestamp: tag.Timestamp}) + infectedTags = append(infectedTags, common.TagInfo{Name: tag.Name, Timestamp: tag.Timestamp, Digest: tag.Digest}) } } var finalTagList []*TagInfo if len(infectedTags) != 0 { - r.cveInfo.Log.Info().Msg("comparing fixed tags timestamp") + r.log.Info().Msg("comparing fixed tags timestamp") - fixedTags := cveinfo.GetFixedTags(tagsInfo, infectedTags) + fixedTags := common.GetFixedTags(tagsInfo, infectedTags) finalTagList = getGraphqlCompatibleTags(fixedTags) } else { - r.cveInfo.Log.Info().Str("image", image).Str("cve-id", id).Msg("image does not contain any tag that have given cve") + r.log.Info().Str("image", image).Str("cve-id", id).Msg("image does not contain any tag that have given cve") finalTagList = getGraphqlCompatibleTags(tagsInfo) } @@ -294,22 +312,24 @@ func (r *queryResolver) ImageListWithCVEFixed(ctx context.Context, id string, im func (r *queryResolver) ImageListForDigest(ctx context.Context, id string) ([]*ImgResultForDigest, error) { imgResultForDigest := []*ImgResultForDigest{} - r.digestInfo.Log.Info().Msg("extracting repositories") + r.log.Info().Msg("extracting repositories") defaultStore := r.storeController.DefaultStore repoList, err := defaultStore.GetRepositories() if err != nil { - r.digestInfo.Log.Error().Err(err).Msg("unable to search repositories") + r.log.Error().Err(err).Msg("unable to search repositories") return imgResultForDigest, err } - r.digestInfo.Log.Info().Msg("scanning each global repository") + r.log.Info().Msg("scanning each global repository") - partialImgResultForDigest, err := r.getImageListForDigest(repoList, id) + rootDir := defaultStore.RootDir() + + partialImgResultForDigest, err := r.getImageListForDigest(rootDir, repoList, id) if err != nil { - r.cveInfo.Log.Error().Err(err).Msg("unable to get image and tag list for global repositories") + r.log.Error().Err(err).Msg("unable to get image and tag list for global repositories") return imgResultForDigest, err } @@ -318,16 +338,18 @@ func (r *queryResolver) ImageListForDigest(ctx context.Context, id string) ([]*I subStore := r.storeController.SubStore for _, store := range subStore { + rootDir := store.RootDir() + subRepoList, err := store.GetRepositories() if err != nil { - r.cveInfo.Log.Error().Err(err).Msg("unable to search sub-repositories") + r.log.Error().Err(err).Msg("unable to search sub-repositories") return imgResultForDigest, err } - partialImgResultForDigest, err = r.getImageListForDigest(subRepoList, id) + partialImgResultForDigest, err = r.getImageListForDigest(rootDir, subRepoList, id) if err != nil { - r.cveInfo.Log.Error().Err(err).Msg("unable to get image and tag list for sub-repositories") + r.log.Error().Err(err).Msg("unable to get image and tag list for sub-repositories") return imgResultForDigest, err } @@ -338,17 +360,19 @@ func (r *queryResolver) ImageListForDigest(ctx context.Context, id string) ([]*I return imgResultForDigest, nil } -func (r *queryResolver) getImageListForDigest(repoList []string, digest string) ([]*ImgResultForDigest, error) { +func (r *queryResolver) getImageListForDigest(rootDir string, repoList []string, + digest string) ([]*ImgResultForDigest, error) { imgResultForDigest := []*ImgResultForDigest{} var errResult error for _, repo := range repoList { - r.digestInfo.Log.Info().Str("repo", repo).Msg("filtering list of tags in image repo by digest") + r.log.Info().Str("repo", repo).Msg("filtering list of tags in image repo by digest") - tags, err := r.digestInfo.GetImageTagsByDigest(repo, digest) + tags, err := r.digestInfo.GetImageTagsByDigest(path.Join(rootDir, repo), digest) if err != nil { - r.digestInfo.Log.Error().Err(err).Msg("unable to get filtered list of image tags") + r.log.Error().Err(err).Msg("unable to get filtered list of image tags") + errResult = err continue @@ -364,15 +388,129 @@ func (r *queryResolver) getImageListForDigest(repoList []string, digest string) return imgResultForDigest, errResult } -func getGraphqlCompatibleTags(fixedTags []cveinfo.TagInfo) []*TagInfo { +func (r *queryResolver) ImageListWithLatestTag(ctx context.Context) ([]*ImageInfo, error) { + r.log.Info().Msg("extension api: finding image list") + + imageList := make([]*ImageInfo, 0) + + defaultStore := r.storeController.DefaultStore + + dsImageList, err := r.getImageListWithLatestTag(defaultStore) + if err != nil { + r.log.Error().Err(err).Msg("extension api: error extracting default store image list") + + return imageList, err + } + + if len(dsImageList) != 0 { + imageList = append(imageList, dsImageList...) + } + + subStore := r.storeController.SubStore + + for _, store := range subStore { + ssImageList, err := r.getImageListWithLatestTag(store) + if err != nil { + r.log.Error().Err(err).Msg("extension api: error extracting default store image list") + + return imageList, err + } + + if len(ssImageList) != 0 { + imageList = append(imageList, ssImageList...) + } + } + + return imageList, nil +} + +func (r *queryResolver) getImageListWithLatestTag(store *storage.ImageStore) ([]*ImageInfo, error) { + results := make([]*ImageInfo, 0) + + repoList, err := store.GetRepositories() + if err != nil { + r.log.Error().Err(err).Msg("extension api: error extracting repositories list") + + return results, err + } + + if len(repoList) == 0 { + r.log.Info().Msg("no repositories found") + } + + dir := store.RootDir() + + layoutUtils := common.NewOciLayoutUtils(r.log) + + for _, repo := range repoList { + tagsInfo, err := layoutUtils.GetImageTagsWithTimestamp(path.Join(dir, repo)) + if err != nil { + r.log.Error().Err(err).Msg("extension api: error getting tag timestamp info") + + return results, err + } + + if len(tagsInfo) == 0 { + r.log.Info().Str("no tagsinfo found for repo", repo).Msg(" continuing traversing") + + continue + } + + latestTag := common.GetLatestTag(tagsInfo) + + digest := godigest.Digest(latestTag.Digest) + + manifest, err := layoutUtils.GetImageBlobManifest(path.Join(dir, repo), digest) + if err != nil { + r.log.Error().Err(err).Msg("extension api: error reading manifest") + + return results, err + } + + size := strconv.FormatInt(manifest.Config.Size, 10) + + name := repo + + imageConfig, err := layoutUtils.GetImageInfo(path.Join(dir, repo), manifest.Config.Digest) + if err != nil { + r.log.Error().Err(err).Msg("extension api: error reading image config") + + return results, err + } + + labels := imageConfig.Config.Labels + + // Read Description + + desc := common.GetDescription(labels) + + // Read licenses + license := common.GetLicense(labels) + + // Read vendor + vendor := common.GetVendor(labels) + + // Read categories + categories := common.GetCategories(labels) + + results = append(results, &ImageInfo{ + Name: &name, Latest: &latestTag.Name, + Description: &desc, Licenses: &license, Vendor: &vendor, + Labels: &categories, Size: &size, LastUpdated: &latestTag.Timestamp, + }) + } + + return results, nil +} + +func getGraphqlCompatibleTags(fixedTags []common.TagInfo) []*TagInfo { finalTagList := make([]*TagInfo, 0) for _, tag := range fixedTags { - copyTag := tag.Name + fixTag := tag - copyTimeStamp := tag.Timestamp - - finalTagList = append(finalTagList, &TagInfo{Name: ©Tag, Timestamp: ©TimeStamp}) + finalTagList = append(finalTagList, + &TagInfo{Name: &fixTag.Name, Digest: &fixTag.Digest, Timestamp: &fixTag.Timestamp}) } return finalTagList diff --git a/pkg/extensions/search/schema.graphql b/pkg/extensions/search/schema.graphql index 6dfe3b18..28ea9d6c 100644 --- a/pkg/extensions/search/schema.graphql +++ b/pkg/extensions/search/schema.graphql @@ -35,12 +35,25 @@ type ImgResultForDigest { type TagInfo { Name: String + Digest: String Timestamp: Time } +type ImageInfo { + Name: String + Latest: String + LastUpdated: Time + Description: String + Licenses: String + Vendor: String + Size: String + Labels: String +} + type Query { CVEListForImage(image: String!) :CVEResultForImage ImageListForCVE(id: String!) :[ImgResultForCVE] ImageListWithCVEFixed(id: String!, image: String!) :ImgResultForFixedCVE ImageListForDigest(id: String!) :[ImgResultForDigest] -} \ No newline at end of file + ImageListWithLatestTag:[ImageInfo] +}