diff options
| -rw-r--r-- | go.mod | 6 | ||||
| -rw-r--r-- | go.sum | 41 | ||||
| -rw-r--r-- | pkg/argocd/update_test.go | 29 | ||||
| -rw-r--r-- | pkg/image/credentials.go | 4 | ||||
| -rw-r--r-- | pkg/registry/client.go | 220 | ||||
| -rw-r--r-- | pkg/registry/client_test.go | 82 | ||||
| -rw-r--r-- | pkg/registry/mocks/RegistryClient.go | 78 | ||||
| -rw-r--r-- | pkg/registry/registry.go | 20 | ||||
| -rw-r--r-- | pkg/registry/registry_test.go | 147 |
9 files changed, 330 insertions, 297 deletions
@@ -7,17 +7,19 @@ require ( github.com/argoproj/argo-cd/v2 v2.1.2 github.com/argoproj/gitops-engine v0.4.1 github.com/argoproj/pkg v0.9.1 + github.com/distribution/distribution/v3 v3.0.0-20210820130019-1cdeff259b9d github.com/docker/distribution v2.7.1+incompatible github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect - github.com/nokia/docker-registry-client v0.0.0-20201015093031-af1a6d3b4fb1 + github.com/opencontainers/go-digest v1.0.0 github.com/patrickmn/go-cache v2.1.0+incompatible github.com/prometheus/client_golang v1.7.1 - github.com/sirupsen/logrus v1.7.0 + github.com/sirupsen/logrus v1.8.1 github.com/spf13/cobra v1.1.3 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.7.0 go.uber.org/ratelimit v0.1.1-0.20201110185707-e86515f0dda9 golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e + golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c gopkg.in/src-d/go-git.v4 v4.13.1 gopkg.in/yaml.v2 v2.4.0 @@ -35,9 +35,11 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX 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= dmitri.shuralyov.com/gpu/mtl v0.0.0-20201218220906-28db891af037/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v43.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.11.12/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= @@ -67,6 +69,7 @@ github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tN github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/TomOnTime/utfutil v0.0.0-20180511104225-09c41003ee1d/go.mod h1:WML6KOYjeU8N6YyusMjj2qRvaPNUEvrQvaxuFcMRFJY= github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= @@ -104,6 +107,7 @@ github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:l github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/auth0/go-jwt-middleware v0.0.0-20170425171159-5493cabe49f7/go.mod h1:LWMyo4iOLWXHGdBki7NIht1kHru/0wM179h+d3g8ATM= github.com/aws/aws-sdk-go v1.33.16/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= +github.com/aws/aws-sdk-go v1.34.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/aws/aws-sdk-go v1.35.24/go.mod h1:tlPOdRjfxPBpNIwqDj61rmsnA85v9jc0Ps9+muhnW+k= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -111,14 +115,20 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= 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/bifurcation/mint v0.0.0-20180715133206-93c51c6ce115/go.mod h1:zVt7zX3K/aDCk9Tj+VM7YymsX66ERvzCJzw8rFCX2JU= +github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= 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/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/bombsimon/logrusr v1.0.0 h1:CTCkURYAt5nhCCnKH9eLShYayj2/8Kn/4Qg3QfiU+Ro= github.com/bombsimon/logrusr v1.0.0/go.mod h1:Jq0nHtvxabKE5EMwAAdgTaz7dfWE8C4i11NOltxGQpc= github.com/bradleyfalzon/ghinstallation v1.1.1 h1:pmBXkxgM1WeF8QYvDLT5kuQiHMcmf+X015GI0KM/E3I= github.com/bradleyfalzon/ghinstallation v1.1.1/go.mod h1:vyCmHTciHx/uuyN82Zc3rXN3X2KTK8nUTCrTMwAhcug= +github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= +github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= +github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= +github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= github.com/caddyserver/caddy v1.0.3/go.mod h1:G+ouvOY32gENkJC+jhgl62TyhvqEsFaDiZ4uw0RzP1E= github.com/casbin/casbin v1.9.1/go.mod h1:z8uPsfBJGUsnkagrt3G8QvjgTKFMBJ32UP8HpZllfog= github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= @@ -178,6 +188,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= +github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= +github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1 h1:CaO/zOnF8VvUfEbhRatPcwKVWamvbYd8tQGRWacE9kU= @@ -185,14 +197,20 @@ github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1/go.mod h1:+hnT3ywWDTAFrW5aE+u2Sa/ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/distribution/distribution/v3 v3.0.0-20210820130019-1cdeff259b9d h1:tU9uEoN7IVTXTznsS/5jUn+Jt7xY9UWTyy9Jp9Rmzc0= +github.com/distribution/distribution/v3 v3.0.0-20210820130019-1cdeff259b9d/go.mod h1:gt38b7cvVKazi5XkHvINNytZXgTEntyhtyM3HQz46Nk= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v20.10.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= +github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4= github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= @@ -339,6 +357,7 @@ github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3K github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= +github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0= github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -510,6 +529,7 @@ github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/malexdev/utfutil v0.0.0-20180510171754-00c8d4a8e7a8/go.mod h1:UtpLyb/EupVKXF/N0b4NRe1DNg+QYJsnsHQ038romhM= github.com/markbates/pkger v0.17.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI= +github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= @@ -544,6 +564,7 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= github.com/moby/ipvs v1.0.1/go.mod h1:2pngiyseZbIKXNv7hsKj3O9UEz30c53MT9005gt2hxQ= github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= @@ -569,10 +590,9 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= +github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nokia/docker-registry-client v0.0.0-20201015093031-af1a6d3b4fb1 h1:QNZos2cYVSeT7m1IEQupD3dWJG3ELuThKQMP3WRDZVE= -github.com/nokia/docker-registry-client v0.0.0-20201015093031-af1a6d3b4fb1/go.mod h1:0DpUaZpSvIXrsvYc6Wb+fKwjhKz0Lu1NHwMziqTqqvA= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= @@ -626,6 +646,7 @@ github.com/pquerna/cachecontrol v0.0.0-20180306154005-525d0eb5f91d/go.mod h1:prY github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.7.1 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -636,6 +657,7 @@ github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6T github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -643,6 +665,7 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.2.0 h1:wH4vA7pcjKuZzjF7lM8awk4fnuJO6idemZXoKnULUx4= github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= @@ -672,8 +695,9 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= @@ -751,6 +775,9 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da h1:NimzV1aGyq29m5ukMK0AMWEhFaL/lrEOaephfuoiARg= github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da/go.mod h1:E1AXubJBdNmFERAOucpDIxNzeGfLzg0mYh+UfMWdChA= +github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= +github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= +github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= @@ -796,6 +823,7 @@ golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -901,8 +929,9 @@ golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 h1:3B43BWw0xEBsLZ/NO1VALz6fppU3481pik+2Ksv45z8= golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f h1:Qmd2pbz05z7z6lm0DrgQVVPuBm92jqujBKMHMOlOQEw= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -939,6 +968,7 @@ golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1075,6 +1105,7 @@ gonum.org/v1/gonum v0.6.2/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= +google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -1100,6 +1131,7 @@ google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCID google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1143,6 +1175,7 @@ google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4 google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= diff --git a/pkg/argocd/update_test.go b/pkg/argocd/update_test.go index d3b9fdc..6cbe6df 100644 --- a/pkg/argocd/update_test.go +++ b/pkg/argocd/update_test.go @@ -33,9 +33,10 @@ func Test_UpdateApplication(t *testing.T) { t.Run("Test successful update", func(t *testing.T) { mockClientFn := func(endpoint *registry.RegistryEndpoint, username, password string) (registry.RegistryClient, error) { regMock := regmock.RegistryClient{} - regMock.On("Tags", mock.MatchedBy(func(s string) bool { + regMock.On("NewRepository", mock.MatchedBy(func(s string) bool { return s == "jannfis/foobar" - })).Return([]string{"1.0.1"}, nil) + })).Return(nil) + regMock.On("Tags").Return([]string{"1.0.1"}, nil) return ®Mock, nil } @@ -91,7 +92,10 @@ func Test_UpdateApplication(t *testing.T) { mockClientFn := func(endpoint *registry.RegistryEndpoint, username, password string) (registry.RegistryClient, error) { regMock := regmock.RegistryClient{} assert.Equal(t, endpoint.RegistryPrefix, "quay.io") - regMock.On("Tags", mock.Anything).Return([]string{"1.0.1"}, nil) + regMock.On("NewRepository", mock.MatchedBy(func(s string) bool { + return s == "jannfis/foobar" + })).Return(nil) + regMock.On("Tags").Return([]string{"1.0.1"}, nil) return ®Mock, nil } @@ -152,9 +156,10 @@ func Test_UpdateApplication(t *testing.T) { mockClientFn := func(endpoint *registry.RegistryEndpoint, username, password string) (registry.RegistryClient, error) { regMock := regmock.RegistryClient{} assert.Equal(t, endpoint.RegistryPrefix, "quay.io") - regMock.On("Tags", mock.MatchedBy(func(s string) bool { + regMock.On("NewRepository", mock.MatchedBy(func(s string) bool { return s == "someorg/foobar" - })).Return([]string{"1.0.1"}, nil) + })).Return(nil) + regMock.On("Tags").Return([]string{"1.0.1"}, nil) return ®Mock, nil } @@ -214,6 +219,7 @@ func Test_UpdateApplication(t *testing.T) { t.Run("Test successful update when no tag is set in running workload", func(t *testing.T) { mockClientFn := func(endpoint *registry.RegistryEndpoint, username, password string) (registry.RegistryClient, error) { regMock := regmock.RegistryClient{} + regMock.On("NewRepository", mock.Anything).Return(nil) regMock.On("Tags", mock.Anything).Return([]string{"1.0.1"}, nil) return ®Mock, nil } @@ -271,6 +277,7 @@ func Test_UpdateApplication(t *testing.T) { regMock := regmock.RegistryClient{} assert.Equal(t, "myuser", username) assert.Equal(t, "mypass", password) + regMock.On("NewRepository", mock.Anything).Return(nil) regMock.On("Tags", mock.Anything).Return([]string{"1.0.1"}, nil) return ®Mock, nil } @@ -384,6 +391,7 @@ func Test_UpdateApplication(t *testing.T) { t.Run("Test skip because of image up-to-date", func(t *testing.T) { mockClientFn := func(endpoint *registry.RegistryEndpoint, username, password string) (registry.RegistryClient, error) { regMock := regmock.RegistryClient{} + regMock.On("NewRepository", mock.Anything).Return(nil) regMock.On("Tags", mock.Anything).Return([]string{"1.0.1"}, nil) return ®Mock, nil } @@ -439,6 +447,7 @@ func Test_UpdateApplication(t *testing.T) { t.Run("Test update because of image registry changed", func(t *testing.T) { mockClientFn := func(endpoint *registry.RegistryEndpoint, username, password string) (registry.RegistryClient, error) { regMock := regmock.RegistryClient{} + regMock.On("NewRepository", mock.Anything).Return(nil) regMock.On("Tags", mock.Anything).Return([]string{"1.0.1"}, nil) return ®Mock, nil } @@ -497,6 +506,7 @@ func Test_UpdateApplication(t *testing.T) { t.Run("Test not updated because kustomize image is the same", func(t *testing.T) { mockClientFn := func(endpoint *registry.RegistryEndpoint, username, password string) (registry.RegistryClient, error) { regMock := regmock.RegistryClient{} + regMock.On("NewRepository", mock.Anything).Return(nil) regMock.On("Tags", mock.Anything).Return([]string{"1.0.1"}, nil) return ®Mock, nil } @@ -569,8 +579,9 @@ func Test_UpdateApplication(t *testing.T) { called := 0 mockClientFn := func(endpoint *registry.RegistryEndpoint, username, password string) (registry.RegistryClient, error) { regMock := regmock.RegistryClient{} + regMock.On("NewRepository", mock.Anything).Return(nil) regMock.On("Tags", mock.Anything).Return([]string{"one", "two", "three", "four"}, nil) - regMock.On("ManifestV1", mock.Anything).Return(meta[called], nil) + regMock.On("Manifest", mock.Anything).Return(meta[called], nil) called += 1 return ®Mock, nil } @@ -644,8 +655,9 @@ func Test_UpdateApplication(t *testing.T) { called := 0 mockClientFn := func(endpoint *registry.RegistryEndpoint, username, password string) (registry.RegistryClient, error) { regMock := regmock.RegistryClient{} + regMock.On("NewRepository", mock.Anything).Return(nil) regMock.On("Tags", mock.Anything).Return([]string{"one", "two", "three", "four"}, nil) - regMock.On("ManifestV1", mock.Anything).Return(meta[called], nil) + regMock.On("Manifest", mock.Anything).Return(meta[called], nil) called += 1 return ®Mock, nil } @@ -705,6 +717,7 @@ func Test_UpdateApplication(t *testing.T) { t.Run("Error - unknown registry", func(t *testing.T) { mockClientFn := func(endpoint *registry.RegistryEndpoint, username, password string) (registry.RegistryClient, error) { regMock := regmock.RegistryClient{} + regMock.On("NewRepository", mock.Anything).Return(nil) regMock.On("Tags", mock.Anything).Return([]string{"1.0.1"}, nil) return ®Mock, nil } @@ -813,6 +826,7 @@ func Test_UpdateApplication(t *testing.T) { t.Run("Test error on failure to list tags", func(t *testing.T) { mockClientFn := func(endpoint *registry.RegistryEndpoint, username, password string) (registry.RegistryClient, error) { regMock := regmock.RegistryClient{} + regMock.On("NewRepository", mock.Anything).Return(nil) regMock.On("Tags", mock.Anything).Return(nil, errors.New("some error")) return ®Mock, nil } @@ -868,6 +882,7 @@ func Test_UpdateApplication(t *testing.T) { t.Run("Test error on improper semver in tag", func(t *testing.T) { mockClientFn := func(endpoint *registry.RegistryEndpoint, username, password string) (registry.RegistryClient, error) { regMock := regmock.RegistryClient{} + regMock.On("NewRepository", mock.Anything).Return(nil) regMock.On("Tags", mock.Anything).Return([]string{"1.0.0", "1.0.1"}, nil) return ®Mock, nil } diff --git a/pkg/image/credentials.go b/pkg/image/credentials.go index 2eb1062..50c3f37 100644 --- a/pkg/image/credentials.go +++ b/pkg/image/credentials.go @@ -229,9 +229,7 @@ func parseDockerConfigJson(registryURL string, jsonSource string) (string, strin regPrefix = registryURL } - if strings.HasSuffix(regPrefix, "/") { - regPrefix = strings.TrimSuffix(regPrefix, "/") - } + regPrefix = strings.TrimSuffix(regPrefix, "/") for registry, authConf := range auths { if !strings.HasPrefix(registry, registryURL) && !strings.HasPrefix(registry, regPrefix) { diff --git a/pkg/registry/client.go b/pkg/registry/client.go index b4dc380..83197e2 100644 --- a/pkg/registry/client.go +++ b/pkg/registry/client.go @@ -1,41 +1,75 @@ package registry import ( - "bytes" + "context" "crypto/sha256" - "crypto/tls" - "encoding/json" "fmt" - "net/http" - "strings" - "time" + + "github.com/argoproj/pkg/json" "github.com/argoproj-labs/argocd-image-updater/pkg/log" "github.com/argoproj-labs/argocd-image-updater/pkg/metrics" "github.com/argoproj-labs/argocd-image-updater/pkg/tag" - "github.com/docker/distribution" - "github.com/docker/distribution/manifest/schema1" - "github.com/docker/distribution/manifest/schema2" - "github.com/nokia/docker-registry-client/registry" + "github.com/distribution/distribution/v3" + "github.com/distribution/distribution/v3/manifest/ocischema" + "github.com/distribution/distribution/v3/manifest/schema1" + "github.com/distribution/distribution/v3/manifest/schema2" + "github.com/distribution/distribution/v3/reference" + "github.com/distribution/distribution/v3/registry/client" + "github.com/distribution/distribution/v3/registry/client/auth" + "github.com/distribution/distribution/v3/registry/client/auth/challenge" + "github.com/distribution/distribution/v3/registry/client/transport" + + "github.com/opencontainers/go-digest" + "go.uber.org/ratelimit" + + "net/http" + "net/url" + "strings" + "time" ) // TODO: Check image's architecture and OS // RegistryClient defines the methods we need for querying container registries type RegistryClient interface { - Tags(nameInRepository string) ([]string, error) - ManifestV1(repository string, reference string) (*schema1.SignedManifest, error) - ManifestV2(repository string, reference string) (*schema2.DeserializedManifest, error) - TagMetadata(repository string, manifest distribution.Manifest) (*tag.TagInfo, error) + NewRepository(nameInRepository string) error + Tags() ([]string, error) + Manifest(tagStr string) (distribution.Manifest, error) + TagMetadata(manifest distribution.Manifest) (*tag.TagInfo, error) } type NewRegistryClient func(*RegistryEndpoint, string, string) (RegistryClient, error) // Helper type for registry clients type registryClient struct { - regClient *registry.Registry + regClient distribution.Repository + endpoint *RegistryEndpoint + creds credentials +} + +// credentials is an implementation of distribution/V3/session struct +// to mangage registry credentials and token +type credentials struct { + username string + password string + refreshTokens map[string]string +} + +func (c credentials) Basic(url *url.URL) (string, string) { + return c.username, c.password +} + +func (c credentials) RefreshToken(url *url.URL, service string) string { + return c.refreshTokens[service] +} + +func (c credentials) SetRefreshToken(realm *url.URL, service, token string) { + if c.refreshTokens != nil { + c.refreshTokens[service] = token + } } // rateLimitTransport encapsulates our custom HTTP round tripper with rate @@ -55,90 +89,84 @@ func (rlt *rateLimitTransport) RoundTrip(r *http.Request) (*http.Response, error return resp, err } -// newRegistry is a wrapper for creating a registry client that is possibly +// NewRepository is a wrapper for creating a registry client that is possibly // rate-limited by using a custom HTTP round tripper method. -func newRegistry(ep *RegistryEndpoint, opts registry.Options) (*registry.Registry, error) { - url := strings.TrimSuffix(ep.RegistryAPI, "/") - var transport http.RoundTripper - if opts.Insecure { - transport = &http.Transport{ - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: true, - }, - } - } else { - transport = http.DefaultTransport +func (clt *registryClient) NewRepository(nameInRepository string) error { + urlToCall := strings.TrimSuffix(clt.endpoint.RegistryAPI, "/") + challengeManager1 := challenge.NewSimpleManager() + _, err := ping(challengeManager1, clt.endpoint.RegistryAPI+"/v2/", "") + if err != nil { + return err } - transport = registry.WrapTransport(transport, url, opts) + var transport http.RoundTripper = transport.NewTransport( + nil, auth.NewAuthorizer( + challengeManager1, + auth.NewTokenHandler(nil, clt.creds, nameInRepository, "pull"))) rlt := &rateLimitTransport{ - limiter: ep.Limiter, + limiter: clt.endpoint.Limiter, transport: transport, - endpoint: ep.RegistryAPI, + endpoint: clt.endpoint.RegistryAPI, } - logf := opts.Logf - if logf == nil { - logf = registry.Log - } - registry := ®istry.Registry{ - URL: url, - Client: &http.Client{ - Transport: rlt, - }, - Logf: logf, + named, err := reference.WithName(nameInRepository) + if err != nil { + return err } - if opts.DoInitialPing { - if err := registry.Ping(); err != nil { - return nil, err - } + clt.regClient, err = client.NewRepository(named, urlToCall, rlt) + if err != nil { + return err } - return registry, nil - + return nil } // NewClient returns a new RegistryClient for the given endpoint information func NewClient(endpoint *RegistryEndpoint, username, password string) (RegistryClient, error) { - if username == "" && endpoint.Username != "" { username = endpoint.Username } if password == "" && endpoint.Password != "" { password = endpoint.Password } - - client, err := newRegistry(endpoint, registry.Options{ - DoInitialPing: endpoint.Ping, - Logf: registry.Quiet, - Username: username, - Password: password, - Insecure: endpoint.Insecure, - }) - if err != nil { - return nil, err + creds := credentials{ + username: username, + password: password, } return ®istryClient{ - regClient: client, + creds: creds, + endpoint: endpoint, }, nil } // Tags returns a list of tags for given name in repository -func (client *registryClient) Tags(nameInRepository string) ([]string, error) { - return client.regClient.Tags(nameInRepository) -} - -// ManifestV1 returns a signed V1 manifest for a given tag in given repository -func (client *registryClient) ManifestV1(repository string, reference string) (*schema1.SignedManifest, error) { - return client.regClient.ManifestV1(repository, reference) +func (clt *registryClient) Tags() ([]string, error) { + tagService := clt.regClient.Tags(context.Background()) + tTags, err := tagService.All(context.Background()) + if err != nil { + return nil, err + } + return tTags, nil } -// ManifestV2 returns a deserialized V2 manifest for a given tag in given repository -func (client *registryClient) ManifestV2(repository string, reference string) (*schema2.DeserializedManifest, error) { - return client.regClient.ManifestV2(repository, reference) +// Manifest returns a Manifest for a given tag in repository +func (clt *registryClient) Manifest(tagStr string) (distribution.Manifest, error) { + manService, err := clt.regClient.Manifests(context.Background()) + if err != nil { + return nil, err + } + mediaType := []string{ocischema.SchemaVersion.MediaType, schema1.SchemaVersion.MediaType, schema2.SchemaVersion.MediaType} + manifest, err := manService.Get( + context.Background(), + digest.FromString(tagStr), + distribution.WithTag(tagStr), distribution.WithManifestMediaTypes(mediaType)) + if err != nil { + return nil, err + } + return manifest, nil } -// GetTagInfo retrieves metadata for a given manifest of given repository -func (client *registryClient) TagMetadata(repository string, manifest distribution.Manifest) (*tag.TagInfo, error) { +// TagMetadata retrieves metadata for a given manifest of given repository +func (client *registryClient) TagMetadata(manifest distribution.Manifest) (*tag.TagInfo, error) { ti := &tag.TagInfo{} var info struct { @@ -146,8 +174,8 @@ func (client *registryClient) TagMetadata(repository string, manifest distributi Created string `json:"created"` OS string `json:"os"` } - - // We support both V1 and V2 manifest schemas. Everything else will trigger + // + // We support both V1,V2 AND OCI manifest schemas. Everything else will trigger // an error. switch deserialized := manifest.(type) { @@ -177,26 +205,37 @@ func (client *registryClient) TagMetadata(repository string, manifest distributi // The data we require from a V2 manifest is in a blob that we need to // fetch from the registry. - _, err := client.regClient.BlobMetadata(repository, man.Config.Digest) + blobReader, err := client.regClient.Blobs(context.Background()).Get(context.Background(), man.Config.Digest) if err != nil { - return nil, fmt.Errorf("could not get metadata: %v", err) + return nil, err } - blobReader, err := client.regClient.DownloadBlob(repository, man.Config.Digest) - if err != nil { + if err := json.Unmarshal(blobReader, &info); err != nil { + return nil, err + } + + if ti.CreatedAt, err = time.Parse(time.RFC3339Nano, info.Created); err != nil { return nil, err } - defer blobReader.Close() - blobBytes := bytes.Buffer{} - n, err := blobBytes.ReadFrom(blobReader) + _, mBytes, err := manifest.Payload() if err != nil { return nil, err } + ti.Digest = sha256.Sum256(mBytes) + log.Tracef("v2 SHA digest is %s", fmt.Sprintf("sha256:%x", ti.Digest)) + return ti, nil + case *ocischema.DeserializedManifest: + var man ocischema.Manifest = deserialized.Manifest - log.Tracef("read %d bytes of blob data for %s", n, repository) + // The data we require from a V2 manifest is in a blob that we need to + // fetch from the registry. + blobReader, err := client.regClient.Blobs(context.Background()).Get(context.Background(), man.Config.Digest) + if err != nil { + return nil, err + } - if err := json.Unmarshal(blobBytes.Bytes(), &info); err != nil { + if err := json.Unmarshal(blobReader, &info); err != nil { return nil, err } @@ -209,10 +248,25 @@ func (client *registryClient) TagMetadata(repository string, manifest distributi return nil, err } ti.Digest = sha256.Sum256(mBytes) - log.Tracef("v2 SHA digest is %s", fmt.Sprintf("sha256:%x", ti.Digest)) + log.Tracef("oci SHA digest is %s", fmt.Sprintf("sha256:%x", ti.Digest)) return ti, nil - default: return nil, fmt.Errorf("invalid manifest type") } } + +// Implementation of ping method to intialize the challenge list +// Without this, tokenHandler and AuthorizationHandler won't work +func ping(manager challenge.Manager, endpoint, versionHeader string) ([]auth.APIVersion, error) { + resp, err := http.Get(endpoint) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if err := manager.AddResponse(resp); err != nil { + return nil, err + } + + return auth.APIVersions(resp, versionHeader), err +} diff --git a/pkg/registry/client_test.go b/pkg/registry/client_test.go new file mode 100644 index 0000000..7d0c3a0 --- /dev/null +++ b/pkg/registry/client_test.go @@ -0,0 +1,82 @@ +package registry + +import ( + "testing" + + "github.com/distribution/distribution/v3/manifest/schema1" + "github.com/stretchr/testify/require" +) + +func Test_TagMetadata(t *testing.T) { + t.Run("Check for correct error handling when manifest contains no history", func(t *testing.T) { + meta1 := &schema1.SignedManifest{ + Manifest: schema1.Manifest{ + History: []schema1.History{}, + }, + } + ep, err := GetRegistryEndpoint("") + require.NoError(t, err) + client, err := NewClient(ep, "", "") + require.NoError(t, err) + _, err = client.TagMetadata(meta1) + require.Error(t, err) + }) + + t.Run("Check for correct error handling when manifest contains invalid history", func(t *testing.T) { + meta1 := &schema1.SignedManifest{ + Manifest: schema1.Manifest{ + History: []schema1.History{ + { + V1Compatibility: `{"created": {"something": "notastring"}}`, + }, + }, + }, + } + + ep, err := GetRegistryEndpoint("") + require.NoError(t, err) + client, err := NewClient(ep, "", "") + require.NoError(t, err) + _, err = client.TagMetadata(meta1) + require.Error(t, err) + }) + + t.Run("Check for correct error handling when manifest contains invalid history", func(t *testing.T) { + meta1 := &schema1.SignedManifest{ + Manifest: schema1.Manifest{ + History: []schema1.History{ + { + V1Compatibility: `{"something": "something"}`, + }, + }, + }, + } + + ep, err := GetRegistryEndpoint("") + require.NoError(t, err) + client, err := NewClient(ep, "", "") + require.NoError(t, err) + _, err = client.TagMetadata(meta1) + require.Error(t, err) + + }) + + t.Run("Check for correct error handling when time stamp cannot be parsed", func(t *testing.T) { + ts := "invalid" + meta1 := &schema1.SignedManifest{ + Manifest: schema1.Manifest{ + History: []schema1.History{ + { + V1Compatibility: `{"created":"` + ts + `"}`, + }, + }, + }, + } + ep, err := GetRegistryEndpoint("") + require.NoError(t, err) + client, err := NewClient(ep, "", "") + require.NoError(t, err) + _, err = client.TagMetadata(meta1) + require.Error(t, err) + }) +} diff --git a/pkg/registry/mocks/RegistryClient.go b/pkg/registry/mocks/RegistryClient.go index 6352903..c6cdb72 100644 --- a/pkg/registry/mocks/RegistryClient.go +++ b/pkg/registry/mocks/RegistryClient.go @@ -3,13 +3,8 @@ package mocks import ( - distribution "github.com/docker/distribution" + distribution "github.com/distribution/distribution/v3" mock "github.com/stretchr/testify/mock" - - schema1 "github.com/docker/distribution/manifest/schema1" - - schema2 "github.com/docker/distribution/manifest/schema2" - tag "github.com/argoproj-labs/argocd-image-updater/pkg/tag" ) @@ -18,22 +13,21 @@ type RegistryClient struct { mock.Mock } -// ManifestV1 provides a mock function with given fields: repository, reference -func (_m *RegistryClient) ManifestV1(repository string, reference string) (*schema1.SignedManifest, error) { - ret := _m.Called(repository, reference) +func (_m *RegistryClient) TagMetadata(manifest distribution.Manifest) (*tag.TagInfo, error) { + ret := _m.Called(manifest) - var r0 *schema1.SignedManifest - if rf, ok := ret.Get(0).(func(string, string) *schema1.SignedManifest); ok { - r0 = rf(repository, reference) + var r0 *tag.TagInfo + if rf, ok := ret.Get(0).(func(distribution.Manifest) *tag.TagInfo); ok { + r0 = rf(manifest) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*schema1.SignedManifest) + r0 = ret.Get(0).(*tag.TagInfo) } } var r1 error - if rf, ok := ret.Get(1).(func(string, string) error); ok { - r1 = rf(repository, reference) + if rf, ok := ret.Get(1).(func(distribution.Manifest) error); ok { + r1 = rf(manifest) } else { r1 = ret.Error(1) } @@ -41,22 +35,21 @@ func (_m *RegistryClient) ManifestV1(repository string, reference string) (*sche return r0, r1 } -// ManifestV2 provides a mock function with given fields: repository, reference -func (_m *RegistryClient) ManifestV2(repository string, reference string) (*schema2.DeserializedManifest, error) { - ret := _m.Called(repository, reference) - - var r0 *schema2.DeserializedManifest - if rf, ok := ret.Get(0).(func(string, string) *schema2.DeserializedManifest); ok { - r0 = rf(repository, reference) +// Tags provides a mock function with given fields: nameInRepository +func (_m *RegistryClient) Tags() ([]string, error) { + ret := _m.Called() + var r0 []string + if rf, ok := ret.Get(0).(func() []string); ok { + r0 = rf() } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*schema2.DeserializedManifest) + r0 = ret.Get(0).([]string) } } var r1 error - if rf, ok := ret.Get(1).(func(string, string) error); ok { - r1 = rf(repository, reference) + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() } else { r1 = ret.Error(1) } @@ -64,22 +57,21 @@ func (_m *RegistryClient) ManifestV2(repository string, reference string) (*sche return r0, r1 } -// TagMetadata provides a mock function with given fields: repository, manifest -func (_m *RegistryClient) TagMetadata(repository string, manifest distribution.Manifest) (*tag.TagInfo, error) { - ret := _m.Called(repository, manifest) +func (_m *RegistryClient) Manifest(tagStr string) (distribution.Manifest, error) { + ret := _m.Called(tagStr) - var r0 *tag.TagInfo - if rf, ok := ret.Get(0).(func(string, distribution.Manifest) *tag.TagInfo); ok { - r0 = rf(repository, manifest) + var r0 distribution.Manifest + if rf, ok := ret.Get(0).(func(string) distribution.Manifest); ok { + r0 = rf(tagStr) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*tag.TagInfo) + r0 = ret.Get(0).(distribution.Manifest) } } var r1 error - if rf, ok := ret.Get(1).(func(string, distribution.Manifest) error); ok { - r1 = rf(repository, manifest) + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(tagStr) } else { r1 = ret.Error(1) } @@ -87,25 +79,15 @@ func (_m *RegistryClient) TagMetadata(repository string, manifest distribution.M return r0, r1 } -// Tags provides a mock function with given fields: nameInRepository -func (_m *RegistryClient) Tags(nameInRepository string) ([]string, error) { +func (_m *RegistryClient) NewRepository(nameInRepository string) (error){ ret := _m.Called(nameInRepository) - var r0 []string - if rf, ok := ret.Get(0).(func(string) []string); ok { - r0 = rf(nameInRepository) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]string) - } - } - var r1 error - if rf, ok := ret.Get(1).(func(string) error); ok { + if rf, ok := ret.Get(0).(func(string) error); ok { r1 = rf(nameInRepository) } else { - r1 = ret.Error(1) + r1 = ret.Error(0) } - return r0, r1 + return r1 } diff --git a/pkg/registry/registry.go b/pkg/registry/registry.go index e39f0d3..c26fe2a 100644 --- a/pkg/registry/registry.go +++ b/pkg/registry/registry.go @@ -12,7 +12,8 @@ import ( "sync" "time" - "github.com/docker/distribution" + "github.com/distribution/distribution/v3" + "golang.org/x/sync/semaphore" "github.com/argoproj-labs/argocd-image-updater/pkg/image" @@ -39,7 +40,11 @@ func (endpoint *RegistryEndpoint) GetTags(img *image.ContainerImage, regClient R } else { nameInRegistry = img.ImageName } - tTags, err := regClient.Tags(nameInRegistry) + err = regClient.NewRepository(nameInRegistry) + if err != nil { + return nil, err + } + tTags, err := regClient.Tags() if err != nil { return nil, err } @@ -131,17 +136,14 @@ func (endpoint *RegistryEndpoint) GetTags(img *image.ContainerImage, regClient R // We first try to fetch a V2 manifest, and if that's not available we fall // back to fetching V1 manifest. If that fails also, we just skip this tag. - if ml, err = regClient.ManifestV2(nameInRegistry, tagStr); err != nil { - log.Debugf("No V2 manifest for %s:%s, fetching V1 (%v)", nameInRegistry, tagStr, err) - if ml, err = regClient.ManifestV1(nameInRegistry, tagStr); err != nil { - log.Errorf("Error fetching metadata for %s:%s - neither V1 or V2 manifest returned by registry: %v", nameInRegistry, tagStr, err) - return - } + if ml, err = regClient.Manifest(tagStr); err != nil { + log.Errorf("Error fetching metadata for %s:%s - neither V1 or V2 or OCI manifest returned by registry: %v", nameInRegistry, tagStr, err) + return } // Parse required meta data from the manifest. The metadata contains all // information needed to decide whether to consider this tag or not. - ti, err := regClient.TagMetadata(nameInRegistry, ml) + ti, err := regClient.TagMetadata(ml) if err != nil { log.Errorf("error fetching metadata for %s:%s: %v", nameInRegistry, tagStr, err) return diff --git a/pkg/registry/registry_test.go b/pkg/registry/registry_test.go index bf52748..fb61077 100644 --- a/pkg/registry/registry_test.go +++ b/pkg/registry/registry_test.go @@ -1,7 +1,6 @@ package registry import ( - "fmt" "os" "testing" "time" @@ -10,8 +9,7 @@ import ( "github.com/argoproj-labs/argocd-image-updater/pkg/registry/mocks" "github.com/argoproj-labs/argocd-image-updater/pkg/tag" - "github.com/docker/distribution/manifest/schema1" - "github.com/docker/distribution/manifest/schema2" + "github.com/distribution/distribution/v3/manifest/schema1" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -21,6 +19,7 @@ func Test_GetTags(t *testing.T) { t.Run("Check for correctly returned tags with semver sort", func(t *testing.T) { regClient := mocks.RegistryClient{} + regClient.On("NewRepository", mock.Anything).Return(nil) regClient.On("Tags", mock.Anything).Return([]string{"1.2.0", "1.2.1", "1.2.2"}, nil) ep, err := GetRegistryEndpoint("") @@ -39,6 +38,7 @@ func Test_GetTags(t *testing.T) { t.Run("Check for correctly returned tags with filter function applied", func(t *testing.T) { regClient := mocks.RegistryClient{} + regClient.On("NewRepository", mock.Anything).Return(nil) regClient.On("Tags", mock.Anything).Return([]string{"1.2.0", "1.2.1", "1.2.2"}, nil) ep, err := GetRegistryEndpoint("") @@ -58,6 +58,7 @@ func Test_GetTags(t *testing.T) { t.Run("Check for correctly returned tags with name sort", func(t *testing.T) { regClient := mocks.RegistryClient{} + regClient.On("NewRepository", mock.Anything).Return(nil) regClient.On("Tags", mock.Anything).Return([]string{"1.2.0", "1.2.1", "1.2.2"}, nil) ep, err := GetRegistryEndpoint("") @@ -85,14 +86,11 @@ func Test_GetTags(t *testing.T) { }, }, } - meta2 := &schema2.DeserializedManifest{ - Manifest: schema2.Manifest{}, - } regClient := mocks.RegistryClient{} + regClient.On("NewRepository", mock.Anything).Return(nil) regClient.On("Tags", mock.Anything).Return([]string{"1.2.0", "1.2.1", "1.2.2"}, nil) - regClient.On("ManifestV1", mock.Anything, mock.Anything).Return(meta1, nil) - regClient.On("ManifestV2", mock.Anything, mock.Anything).Return(meta2, nil) + regClient.On("Manifest", mock.Anything, mock.Anything).Return(meta1, nil) regClient.On("TagMetadata", mock.Anything, mock.Anything).Return(&tag.TagInfo{}, nil) ep, err := GetRegistryEndpoint("") @@ -110,139 +108,6 @@ func Test_GetTags(t *testing.T) { require.Equal(t, "1.2.1", tag.TagName) }) - t.Run("Check for correct error handling when manifest contains no history", func(t *testing.T) { - meta1 := &schema1.SignedManifest{ - Manifest: schema1.Manifest{ - History: []schema1.History{}, - }, - } - meta2 := &schema2.DeserializedManifest{ - Manifest: schema2.Manifest{}, - } - - regClient := mocks.RegistryClient{} - regClient.On("Tags", mock.Anything).Return([]string{"1.2.0", "1.2.1", "1.2.2"}, nil) - regClient.On("ManifestV1", mock.Anything, mock.Anything).Return(meta1, nil) - regClient.On("ManifestV2", mock.Anything, mock.Anything).Return(meta2, fmt.Errorf("not implemented")) - regClient.On("TagMetadata", mock.Anything, mock.Anything).Return(nil, nil) - - ep, err := GetRegistryEndpoint("") - require.NoError(t, err) - ep.Cache.ClearCache() - - img := image.NewFromIdentifier("foo/bar:1.2.0") - tl, err := ep.GetTags(img, ®Client, &image.VersionConstraint{SortMode: image.VersionSortLatest}) - require.NoError(t, err) - assert.Empty(t, tl.Tags()) - - tag, err := ep.Cache.GetTag("foo/bar", "1.2.1") - require.NoError(t, err) - require.Nil(t, tag) - }) - - t.Run("Check for correct error handling when manifest contains invalid history", func(t *testing.T) { - meta1 := &schema1.SignedManifest{ - Manifest: schema1.Manifest{ - History: []schema1.History{ - { - V1Compatibility: `{"created": {"something": "notastring"}}`, - }, - }, - }, - } - meta2 := &schema2.DeserializedManifest{ - Manifest: schema2.Manifest{}, - } - - regClient := mocks.RegistryClient{} - regClient.On("Tags", mock.Anything).Return([]string{"1.2.0", "1.2.1", "1.2.2"}, nil) - regClient.On("ManifestV1", mock.Anything, mock.Anything).Return(meta1, nil) - regClient.On("ManifestV2", mock.Anything, mock.Anything).Return(meta2, fmt.Errorf("not implemented")) - regClient.On("TagMetadata", mock.Anything, mock.Anything).Return(nil, nil) - - ep, err := GetRegistryEndpoint("") - require.NoError(t, err) - ep.Cache.ClearCache() - - img := image.NewFromIdentifier("foo/bar:1.2.0") - tl, err := ep.GetTags(img, ®Client, &image.VersionConstraint{SortMode: image.VersionSortLatest}) - require.NoError(t, err) - assert.Empty(t, tl.Tags()) - - tag, err := ep.Cache.GetTag("foo/bar", "1.2.1") - require.NoError(t, err) - require.Nil(t, tag) - }) - - t.Run("Check for correct error handling when manifest contains invalid history", func(t *testing.T) { - meta1 := &schema1.SignedManifest{ - Manifest: schema1.Manifest{ - History: []schema1.History{ - { - V1Compatibility: `{"something": "something"}`, - }, - }, - }, - } - meta2 := &schema2.DeserializedManifest{ - Manifest: schema2.Manifest{}, - } - - regClient := mocks.RegistryClient{} - regClient.On("Tags", mock.Anything).Return([]string{"1.2.0", "1.2.1", "1.2.2"}, nil) - regClient.On("ManifestV1", mock.Anything, mock.Anything).Return(meta1, nil) - regClient.On("ManifestV2", mock.Anything, mock.Anything).Return(meta2, fmt.Errorf("not implemented")) - regClient.On("TagMetadata", mock.Anything, mock.Anything).Return(nil, nil) - - ep, err := GetRegistryEndpoint("") - require.NoError(t, err) - ep.Cache.ClearCache() - - img := image.NewFromIdentifier("foo/bar:1.2.0") - tl, err := ep.GetTags(img, ®Client, &image.VersionConstraint{SortMode: image.VersionSortLatest}) - require.NoError(t, err) - assert.Empty(t, tl.Tags()) - - tag, err := ep.Cache.GetTag("foo/bar", "1.2.1") - require.NoError(t, err) - require.Nil(t, tag) - }) - - t.Run("Check for correct error handling when time stamp cannot be parsed", func(t *testing.T) { - ts := "invalid" - meta1 := &schema1.SignedManifest{ - Manifest: schema1.Manifest{ - History: []schema1.History{ - { - V1Compatibility: `{"created":"` + ts + `"}`, - }, - }, - }, - } - meta2 := &schema2.DeserializedManifest{ - Manifest: schema2.Manifest{}, - } - - regClient := mocks.RegistryClient{} - regClient.On("Tags", mock.Anything).Return([]string{"1.2.0", "1.2.1", "1.2.2"}, nil) - regClient.On("ManifestV1", mock.Anything, mock.Anything).Return(meta1, nil) - regClient.On("ManifestV2", mock.Anything, mock.Anything).Return(meta2, fmt.Errorf("not implemented")) - regClient.On("TagMetadata", mock.Anything, mock.Anything).Return(nil, nil) - - ep, err := GetRegistryEndpoint("") - require.NoError(t, err) - ep.Cache.ClearCache() - - img := image.NewFromIdentifier("foo/bar:1.2.0") - tl, err := ep.GetTags(img, ®Client, &image.VersionConstraint{SortMode: image.VersionSortLatest}) - require.NoError(t, err) - assert.Empty(t, tl.Tags()) - - tag, err := ep.Cache.GetTag("foo/bar", "1.2.1") - require.NoError(t, err) - require.Nil(t, tag) - }) - } func Test_ExpireCredentials(t *testing.T) { |
