mirror of
https://github.com/project-zot/zot.git
synced 2024-12-16 21:56:37 -05:00
search: added graphql api to return repository list with latest tag
This commit is contained in:
parent
0b302d9614
commit
63fef3e48c
16 changed files with 1775 additions and 640 deletions
|
@ -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")
|
||||
)
|
||||
|
|
16
go.mod
16
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
|
||||
|
|
53
go.sum
53
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=
|
||||
|
|
|
@ -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)))
|
||||
}
|
||||
|
|
155
pkg/extensions/search/common/common.go
Normal file
155
pkg/extensions/search/common/common.go
Normal file
|
@ -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
|
||||
}
|
460
pkg/extensions/search/common/common_test.go
Normal file
460
pkg/extensions/search/common/common_test.go
Normal file
|
@ -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)
|
||||
})
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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"`
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
}
|
||||
ImageListWithLatestTag:[ImageInfo]
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue