diff --git a/go.mod b/go.mod index e74e80be7..6745077c9 100644 --- a/go.mod +++ b/go.mod @@ -17,6 +17,7 @@ require ( github.com/fatih/color v1.17.0 github.com/go-sql-driver/mysql v1.8.1 github.com/gocarina/gocsv v0.0.0-20220927221512-ad3251f9fa25 + github.com/google/go-containerregistry v0.21.3 github.com/hashicorp/go-retryablehttp v0.7.7 github.com/hashicorp/go-version v1.6.0 github.com/jackc/pgx/v5 v5.7.4 @@ -31,13 +32,13 @@ require ( github.com/redis/go-redis/v9 v9.7.3 github.com/shirou/gopsutil v3.21.11+incompatible github.com/sijms/go-ora/v2 v2.8.22 - github.com/spf13/cobra v1.9.1 - github.com/spf13/pflag v1.0.7 + github.com/spf13/cobra v1.10.2 + github.com/spf13/pflag v1.0.10 github.com/spf13/viper v1.13.0 github.com/stretchr/testify v1.11.1 go.etcd.io/etcd/client/v3 v3.5.21 go.mongodb.org/mongo-driver v1.14.0 - golang.org/x/mod v0.33.0 + golang.org/x/mod v0.34.0 golang.org/x/sys v0.42.0 google.golang.org/grpc v1.79.3 google.golang.org/protobuf v1.36.11 @@ -87,6 +88,7 @@ require ( github.com/containerd/errdefs/pkg v0.3.0 // indirect github.com/containerd/log v0.1.0 // indirect github.com/containerd/platforms v0.2.1 // indirect + github.com/containerd/stargz-snapshotter/estargz v0.18.2 // indirect github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cyphar/filepath-securejoin v0.6.1 // indirect @@ -96,6 +98,9 @@ require ( github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/distribution/reference v0.6.0 // indirect github.com/dlclark/regexp2 v1.11.0 // indirect + github.com/docker/cli v29.3.0+incompatible // indirect + github.com/docker/distribution v2.8.3+incompatible // indirect + github.com/docker/docker-credential-helpers v0.9.3 // indirect github.com/docker/go-connections v0.6.0 // indirect github.com/docker/go-events v0.0.0-20250808211157-605354379745 // indirect github.com/docker/go-units v0.5.0 // indirect @@ -153,7 +158,7 @@ require ( github.com/jmoiron/sqlx v1.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.18.3 // indirect + github.com/klauspost/compress v1.18.4 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect github.com/lestrrat-go/blackmagic v1.0.2 // indirect @@ -170,6 +175,7 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect @@ -216,6 +222,7 @@ require ( github.com/tklauser/go-sysconf v0.3.16 // indirect github.com/tklauser/numcpus v0.11.0 // indirect github.com/tmc/langchaingo v0.1.15-0.20251029190607-e35755df7084 // indirect + github.com/vbatts/tar-split v0.12.2 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.1.2 // indirect @@ -244,7 +251,7 @@ require ( golang.org/x/crypto v0.49.0 // indirect golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect golang.org/x/net v0.52.0 // indirect - golang.org/x/oauth2 v0.34.0 // indirect + golang.org/x/oauth2 v0.36.0 // indirect golang.org/x/sync v0.20.0 // indirect golang.org/x/term v0.41.0 // indirect golang.org/x/text v0.35.0 // indirect diff --git a/go.sum b/go.sum index b0fd4bb41..86d37d1fb 100644 --- a/go.sum +++ b/go.sum @@ -149,6 +149,8 @@ github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= +github.com/containerd/stargz-snapshotter/estargz v0.18.2 h1:yXkZFYIzz3eoLwlTUZKz2iQ4MrckBxJjkmD16ynUTrw= +github.com/containerd/stargz-snapshotter/estargz v0.18.2/go.mod h1:XyVU5tcJ3PRpkA9XS2T5us6Eg35yM0214Y+wvrZTBrY= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= @@ -184,10 +186,14 @@ github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5Qvfr github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/docker/cli v29.3.0+incompatible h1:z3iWveU7h19Pqx7alZES8j+IeFQZ1lhTwb2F+V9SVvk= +github.com/docker/cli v29.3.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= +github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM= github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo= -github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M= +github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8= +github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo= github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94= github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE= github.com/docker/go-events v0.0.0-20250808211157-605354379745 h1:yOn6Ze6IbYI/KAw2lw/83ELYvZh6hvsygTVkD0dzMC4= @@ -346,6 +352,8 @@ github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/go-containerregistry v0.21.3 h1:Xr+yt3VvwOOn/5nJzd7UoOhwPGiPkYW0zWDLLUXqAi4= +github.com/google/go-containerregistry v0.21.3/go.mod h1:D5ZrJF1e6dMzvInpBPuMCX0FxURz7GLq2rV3Us9aPkc= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -435,8 +443,8 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw= -github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= +github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/kolesnikovae/go-winjob v1.0.0 h1:OKEtCHB3sYNAiqNwGDhf08Y6luM7C8mP+42rp1N6SeE= github.com/kolesnikovae/go-winjob v1.0.0/go.mod h1:k0joOLP3/NBrRmDQjPV2+oN1TPmEWt6arTNtFjVeQuM= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -493,6 +501,8 @@ github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM= github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc= github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= @@ -639,13 +649,13 @@ github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA= github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo= github.com/spf13/cast v1.8.0 h1:gEN9K4b8Xws4EX0+a0reLmhq8moKn7ntRlQYgjPeCDk= github.com/spf13/cast v1.8.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= -github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= -github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= +github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= +github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M= -github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.13.0 h1:BWSJ/M+f+3nmdz9bxB+bWX28kkALN2ok11D0rSo8EJU= github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw= github.com/spiffe/go-spiffe/v2 v2.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo= @@ -679,6 +689,8 @@ github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9R github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ= github.com/tmc/langchaingo v0.1.15-0.20251029190607-e35755df7084 h1:e7m315AqnlqGh/c7Dc1+pn8rFNONmXToKgaUrXdj2hM= github.com/tmc/langchaingo v0.1.15-0.20251029190607-e35755df7084/go.mod h1:aKKYXYoqhIDEv7WKdpnnCLRaqXic69cX9MnDUk72378= +github.com/vbatts/tar-split v0.12.2 h1:w/Y6tjxpeiFMR47yzZPlPj/FcPLpXbTUi/9H7d3CPa4= +github.com/vbatts/tar-split v0.12.2/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= @@ -818,8 +830,8 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= -golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= +golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI= +golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -864,8 +876,8 @@ golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= -golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= +golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= 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= @@ -996,8 +1008,8 @@ golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= -golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= +golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s= +golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/pkg/kubernetes/kubernetes.go b/pkg/kubernetes/kubernetes.go index fd0ef4c62..5361cb199 100644 --- a/pkg/kubernetes/kubernetes.go +++ b/pkg/kubernetes/kubernetes.go @@ -174,15 +174,15 @@ func helmConfig(namespace string) (*helm.Configuration, error) { return &ac, err } -func getVersion(releaseName string, version string) (string, error) { +func getVersion(releaseName string, version string, imageRegistryURI string) (string, error) { actualVersion := version if version == latestVersion { var err error switch releaseName { case daprReleaseName: - actualVersion, err = cli_ver.GetDaprVersion() + actualVersion, err = cli_ver.GetLatestVersion(cli_ver.DaprImageRef(imageRegistryURI)) case dashboardReleaseName: - actualVersion, err = cli_ver.GetDashboardVersion() + actualVersion, err = cli_ver.GetLatestVersion(cli_ver.DashboardImageRef(imageRegistryURI)) default: return "", fmt.Errorf("cannot get latest version for unknown chart: %s", releaseName) } @@ -297,7 +297,7 @@ func install(releaseName, releaseVersion, helmRepo string, config InitConfigurat return err } - version, err := getVersion(releaseName, releaseVersion) + version, err := getVersion(releaseName, releaseVersion, config.ImageRegistryURI) if err != nil { return err } diff --git a/pkg/standalone/standalone.go b/pkg/standalone/standalone.go index 391d4b392..2a1e81ca2 100644 --- a/pkg/standalone/standalone.go +++ b/pkg/standalone/standalone.go @@ -212,15 +212,24 @@ func Init(runtimeVersion, dashboardVersion string, dockerNetwork string, slimMod // Set runtime version. + // Determine the effective registry URL for version resolution. + // When no custom registry is provided, use the default registry + // (GHCR or Docker Hub) so we query tags from the same registry + // that will be used for pulling images. + effectiveRegistryURL := imageRegistryURL + if effectiveRegistryURL == "" && defaultImageRegistryName == githubContainerRegistryName { + effectiveRegistryURL = ghcrURI + } + if runtimeVersion == latestVersion && !isAirGapInit { - runtimeVersion, err = cli_ver.GetDaprVersion() + runtimeVersion, err = cli_ver.GetLatestVersion(cli_ver.DaprImageRef(effectiveRegistryURL)) if err != nil { return fmt.Errorf("cannot get the latest release version: '%w'. Try specifying --runtime-version=", err) } } if dashboardVersion == latestVersion && !isAirGapInit { - dashboardVersion, err = cli_ver.GetDashboardVersion() + dashboardVersion, err = cli_ver.GetLatestVersion(cli_ver.DashboardImageRef(effectiveRegistryURL)) if err != nil { print.WarningStatusEvent(os.Stdout, "cannot get the latest dashboard version: '%s'. Try specifying --dashboard-version=", err) print.WarningStatusEvent(os.Stdout, "continuing, but dashboard will be unavailable") diff --git a/pkg/version/version.go b/pkg/version/version.go index 4c0254e9a..4d3d0f675 100644 --- a/pkg/version/version.go +++ b/pkg/version/version.go @@ -14,19 +14,13 @@ limitations under the License. package version import ( - "encoding/json" - "errors" "fmt" - "io" - "net/http" - "os" "strings" - "github.com/hashicorp/go-version" - yaml "gopkg.in/yaml.v2" - - "github.com/dapr/cli/pkg/print" - "github.com/dapr/cli/utils" + "github.com/google/go-containerregistry/pkg/authn" + "github.com/google/go-containerregistry/pkg/name" + "github.com/google/go-containerregistry/pkg/v1/remote" + goversion "github.com/hashicorp/go-version" ) const ( @@ -36,137 +30,68 @@ const ( DaprGitHubRepo = "dapr" // DashboardGitHubRepo is the repo name of dapr dashboard on GitHub. DashboardGitHubRepo = "dashboard" -) - -type githubRepoReleaseItem struct { - URL string `json:"url"` - TagName string `json:"tag_name"` - Name string `json:"name"` - Draft bool `json:"draft"` -} - -type helmChartItems struct { - Entries struct { - Dapr []struct { - Version string `yaml:"appVersion"` - } - DaprDashboard []struct { - Version string `yaml:"appVersion"` - } `yaml:"dapr-dashboard"` - } -} -func GetDashboardVersion() (string, error) { - return GetLatestReleaseGithub(fmt.Sprintf("https://api.github.com/repos/%s/%s/releases", DaprGitHubOrg, DashboardGitHubRepo)) -} + // Default container image references used for version resolution. + DaprDefaultImage = "daprio/dapr" + DashboardDefaultImage = "daprio/dashboard" +) -func GetDaprVersion() (string, error) { - version, err := GetLatestReleaseGithub(fmt.Sprintf("https://api.github.com/repos/%s/%s/releases", DaprGitHubOrg, DaprGitHubRepo)) +// GetLatestVersion lists tags on the given container image reference +// and returns the highest semver, non-prerelease version. +func GetLatestVersion(imageRef string) (string, error) { + repo, err := name.NewRepository(imageRef) if err != nil { - print.WarningStatusEvent(os.Stdout, "Failed to get runtime version: '%s'. Trying secondary source", err) - - version, err = GetLatestReleaseHelmChart("https://dapr.github.io/helm-charts/index.yaml") - if err != nil { - return "", err - } + return "", fmt.Errorf("invalid image reference %q: %w", imageRef, err) } - return version, nil -} - -func GetVersionFromURL(releaseURL string, parseVersion func(body []byte) (string, error)) (string, error) { - req, err := http.NewRequest(http.MethodGet, releaseURL, nil) + tags, err := remote.List(repo, remote.WithAuthFromKeychain(authn.DefaultKeychain)) if err != nil { - return "", err - } - - githubToken := utils.GetEnv("GITHUB_TOKEN", "") - if githubToken != "" { - req.Header.Add("Authorization", "token "+githubToken) + return "", fmt.Errorf("failed to list tags for %q: %w", imageRef, err) } - resp, err := http.DefaultClient.Do(req) - if err != nil { - return "", err + if len(tags) == 0 { + return "", fmt.Errorf("no tags found for %q", imageRef) } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - return "", fmt.Errorf("%s - %s", releaseURL, resp.Status) - } + defaultVersion, _ := goversion.NewVersion("0.0.0") + latestVersion := defaultVersion - body, err := io.ReadAll(resp.Body) - if err != nil { - return "", err - } - - return parseVersion(body) -} - -// GetLatestReleaseGithub return the latest release version of dapr from GitHub API. -func GetLatestReleaseGithub(githubURL string) (string, error) { - return GetVersionFromURL(githubURL, func(body []byte) (string, error) { - var githubRepoReleases []githubRepoReleaseItem - err := json.Unmarshal(body, &githubRepoReleases) - if err != nil { - return "", err + for _, tag := range tags { + cur, err := goversion.NewVersion(strings.TrimPrefix(tag, "v")) + if err != nil || cur == nil { + continue } - - if len(githubRepoReleases) == 0 { - return "", errors.New("no releases") + if cur.Prerelease() != "" || cur.Metadata() != "" { + continue } - - defaultVersion, _ := version.NewVersion("0.0.0") - latestVersion := defaultVersion - - for _, release := range githubRepoReleases { - cur, err := version.NewVersion(strings.TrimPrefix(release.TagName, "v")) - if err != nil || cur == nil { - print.WarningStatusEvent(os.Stdout, "Malformed version %s, skipping", release.TagName) - continue - } - // Prerelease versions and versions with metadata are skipped. - if cur.Prerelease() != "" || cur.Metadata() != "" { - continue - } - - if cur.GreaterThan(latestVersion) { - latestVersion = cur - } + if cur.GreaterThan(latestVersion) { + latestVersion = cur } + } - if latestVersion.Equal(defaultVersion) { - return "", errors.New("no releases") - } + if latestVersion.Equal(defaultVersion) { + return "", fmt.Errorf("no stable releases found for %q", imageRef) + } - return latestVersion.String(), nil - }) + return latestVersion.String(), nil } -// GetLatestReleaseHelmChart return the latest release version of dapr from helm chart static index.yaml. -func GetLatestReleaseHelmChart(helmChartURL string) (string, error) { - return GetVersionFromURL(helmChartURL, func(body []byte) (string, error) { - var helmChartReleases helmChartItems - err := yaml.Unmarshal(body, &helmChartReleases) - if err != nil { - return "", err - } - if len(helmChartReleases.Entries.Dapr) == 0 { - return "", errors.New("no releases") - } - - for _, release := range helmChartReleases.Entries.Dapr { - if !strings.Contains(release.Version, "-rc") { - return release.Version, nil - } - } - - // Did not find a non-rc version, so we fallback to an RC. - // This is helpful to allow us to validate installation of new charts (Dashboard). - for _, release := range helmChartReleases.Entries.Dapr { - return release.Version, nil - } +// DaprImageRef returns the full image reference for the Dapr runtime image +// based on the provided custom registry URL. If empty, it falls back to +// the default Docker Hub image. +func DaprImageRef(imageRegistryURL string) string { + if imageRegistryURL != "" { + return imageRegistryURL + "/dapr/dapr" + } + return DaprDefaultImage +} - return "", errors.New("no releases") - }) +// DashboardImageRef returns the full image reference for the Dapr dashboard +// image based on the provided custom registry URL. If empty, it falls back +// to the default Docker Hub image. +func DashboardImageRef(imageRegistryURL string) string { + if imageRegistryURL != "" { + return imageRegistryURL + "/dapr/dashboard" + } + return DashboardDefaultImage } diff --git a/pkg/version/version_test.go b/pkg/version/version_test.go index e49a71148..5bbf59fbd 100644 --- a/pkg/version/version_test.go +++ b/pkg/version/version_test.go @@ -15,331 +15,191 @@ package version import ( "fmt" - "net/http" + "net/http/httptest" + "strings" "testing" - "time" + "github.com/google/go-containerregistry/pkg/crane" + "github.com/google/go-containerregistry/pkg/name" + "github.com/google/go-containerregistry/pkg/registry" + "github.com/google/go-containerregistry/pkg/v1/empty" + "github.com/google/go-containerregistry/pkg/v1/mutate" + v1 "github.com/google/go-containerregistry/pkg/v1/types" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) -func TestGetVersionsGithub(t *testing.T) { - // Ensure a clean environment. +// pushEmptyImage pushes a minimal image with the given tag to the test registry. +func pushEmptyImage(t *testing.T, ref string) { + t.Helper() + img := mutate.MediaType(empty.Image, v1.DockerManifestSchema2) + err := crane.Push(img, ref) + require.NoError(t, err, "failed to push image %s", ref) +} + +// startTestRegistry starts an in-memory OCI registry and returns the +// host:port string (without scheme) and a cleanup function. +func startTestRegistry(t *testing.T) string { + t.Helper() + srv := httptest.NewServer(registry.New()) + t.Cleanup(srv.Close) + // httptest URLs are http://host:port — strip the scheme for use as a registry. + return strings.TrimPrefix(srv.URL, "http://") +} +func TestGetLatestVersion(t *testing.T) { tests := []struct { - Name string - Path string - ResponseBody string - ExpectedErr string - ExpectedVer string + name string + tags []string + expectedVer string + expectedErr string }{ { - "RC releases are skipped", - "/no_rc", - `[ - { - "url": "https://api.github.com/repos/dapr/dapr/releases/44766923", - "html_url": "https://github.com/dapr/dapr/releases/tag/v1.2.3-rc.1", - "id": 44766926, - "tag_name": "v1.2.3-rc.1", - "target_commitish": "master", - "name": "Dapr Runtime v1.2.3-rc.1", - "draft": false, - "prerelease": false - }, - { - "url": "https://api.github.com/repos/dapr/dapr/releases/44766923", - "html_url": "https://github.com/dapr/dapr/releases/tag/v1.2.2", - "id": 44766923, - "tag_name": "v1.2.2", - "target_commitish": "master", - "name": "Dapr Runtime v1.2.2", - "draft": false, - "prerelease": false - } -] - `, - "", - "1.2.2", + name: "RC releases are skipped", + tags: []string{"v1.2.3-rc.1", "v1.2.2"}, + expectedVer: "1.2.2", }, { - "Only latest version is got", - "/latest", - `[ - { - "url": "https://api.github.com/repos/dapr/dapr/releases/44766923", - "html_url": "https://github.com/dapr/dapr/releases/tag/v1.4.4", - "id": 44766926, - "tag_name": "v1.4.4", - "target_commitish": "master", - "name": "Dapr Runtime v1.4.4", - "draft": false, - "prerelease": false - }, - { - "url": "https://api.github.com/repos/dapr/dapr/releases/44766923", - "html_url": "https://github.com/dapr/dapr/releases/tag/v1.5.1", - "id": 44766923, - "tag_name": "v1.5.1", - "target_commitish": "master", - "name": "Dapr Runtime v1.5.1", - "draft": false, - "prerelease": false - } -] - `, - "", - "1.5.1", + name: "Only latest version is returned", + tags: []string{"v1.4.4", "v1.5.1"}, + expectedVer: "1.5.1", }, { - "Only latest stable version is got", - "/latest_stable", - `[ - { - "url": "https://api.github.com/repos/dapr/dapr/releases/44766923", - "html_url": "https://github.com/dapr/dapr/releases/tag/v1.5.2-rc.1", - "id": 44766926, - "tag_name": "v1.5.2-rc.1", - "target_commitish": "master", - "name": "Dapr Runtime v1.5.2-rc.1", - "draft": false, - "prerelease": true - }, - { - "url": "https://api.github.com/repos/dapr/dapr/releases/44766923", - "html_url": "https://github.com/dapr/dapr/releases/tag/v1.4.4", - "id": 44766926, - "tag_name": "v1.4.4", - "target_commitish": "master", - "name": "Dapr Runtime v1.4.4", - "draft": false, - "prerelease": false - }, - { - "url": "https://api.github.com/repos/dapr/dapr/releases/44766923", - "html_url": "https://github.com/dapr/dapr/releases/tag/v1.5.1", - "id": 44766923, - "tag_name": "v1.5.1", - "target_commitish": "master", - "name": "Dapr Runtime v1.5.1", - "draft": false, - "prerelease": false - } -] - `, - "", - "1.5.1", + name: "Only latest stable version is returned", + tags: []string{"v1.5.2-rc.1", "v1.4.4", "v1.5.1"}, + expectedVer: "1.5.1", }, { - "Malformed JSON", - "/malformed", - "[", - "unexpected end of JSON input", - "", + name: "Tags without v prefix work", + tags: []string{"1.4.4", "1.5.1"}, + expectedVer: "1.5.1", }, { - "Only RCs", - "/only_rcs", - `[ - { - "url": "https://api.github.com/repos/dapr/dapr/releases/44766923", - "html_url": "https://github.com/dapr/dapr/releases/tag/v1.2.3-rc.1", - "id": 44766926, - "tag_name": "v1.2.3-rc.1", - "target_commitish": "master", - "name": "Dapr Runtime v1.2.3-rc.1", - "draft": false, - "prerelease": false - } -] `, - "no releases", - "", + name: "Only RCs returns error", + tags: []string{"v1.2.3-rc.1"}, + expectedErr: "no stable releases found", }, { - "Empty json", - "/empty", - "[]", - "no releases", - "", + name: "Malformed version tags are skipped", + tags: []string{"vedge", "latest", "v1.5.1"}, + expectedVer: "1.5.1", }, { - "Malformed version no releases", - "/malformed_version_no_releases", - `[ - { - "url": "https://api.github.com/repos/dapr/dapr/releases/186741665", - "html_url": "https://github.com/dapr/dapr/releases/tag/vedge", - "id": 186741665, - "tag_name": "vedge", - "target_commitish": "master", - "name": "Dapr Runtime vedge", - "draft": false, - "prerelease": false - } -] `, - "no releases", - "", - }, - { - "Malformed version with latest", - "/malformed_version_with_latest", - `[ - { - "url": "https://api.github.com/repos/dapr/dapr/releases/186741665", - "html_url": "https://github.com/dapr/dapr/releases/tag/vedge", - "id": 186741665, - "tag_name": "vedge", - "target_commitish": "master", - "name": "Dapr Runtime vedge", - "draft": false, - "prerelease": false - }, - { - "url": "https://api.github.com/repos/dapr/dapr/releases/44766923", - "html_url": "https://github.com/dapr/dapr/releases/tag/v1.5.1", - "id": 44766923, - "tag_name": "v1.5.1", - "target_commitish": "master", - "name": "Dapr Runtime v1.5.1", - "draft": false, - "prerelease": false - } -] `, - "", - "1.5.1", + name: "Only malformed tags returns error", + tags: []string{"vedge", "latest"}, + expectedErr: "no stable releases found", }, } - m := http.NewServeMux() - s := http.Server{Addr: ":12345", Handler: m, ReadHeaderTimeout: time.Duration(5) * time.Second} for _, tc := range tests { - body := tc.ResponseBody - m.HandleFunc(tc.Path, func(w http.ResponseWriter, r *http.Request) { - fmt.Fprint(w, body) - }) - } + t.Run(tc.name, func(t *testing.T) { + host := startTestRegistry(t) + imageRef := fmt.Sprintf("%s/dapr/dapr", host) - go func() { - s.ListenAndServe() - }() + for _, tag := range tc.tags { + pushEmptyImage(t, fmt.Sprintf("%s:%s", imageRef, tag)) + } - for _, tc := range tests { - t.Run(tc.Name, func(t *testing.T) { - version, err := GetLatestReleaseGithub("http://localhost:12345" + tc.Path) - assert.Equal(t, tc.ExpectedVer, version) - if tc.ExpectedErr != "" { - assert.EqualError(t, err, tc.ExpectedErr) + ver, err := GetLatestVersion(imageRef) + if tc.expectedErr != "" { + assert.ErrorContains(t, err, tc.expectedErr) + assert.Empty(t, ver) + } else { + require.NoError(t, err) + assert.Equal(t, tc.expectedVer, ver) } }) } +} - t.Run("error on 404", func(t *testing.T) { - version, err := GetLatestReleaseGithub("http://localhost:12345/non-existant/path") - assert.Equal(t, "", version) - assert.EqualError(t, err, "http://localhost:12345/non-existant/path - 404 Not Found") - }) +func TestGetLatestVersionNoTags(t *testing.T) { + host := startTestRegistry(t) + imageRef := fmt.Sprintf("%s/dapr/nonexistent", host) - t.Run("error on bad addr", func(t *testing.T) { - version, err := GetLatestReleaseGithub("http://a.super.non.existant.domain/") - assert.Equal(t, "", version) - assert.Error(t, err) - }) + ver, err := GetLatestVersion(imageRef) + assert.Error(t, err) + assert.Empty(t, ver) +} - s.Shutdown(t.Context()) +func TestGetLatestVersionInvalidRef(t *testing.T) { + ver, err := GetLatestVersion("://invalid") + assert.Error(t, err) + assert.Empty(t, ver) } -func TestGetVersionsHelm(t *testing.T) { - // Ensure a clean environment. +func TestGetLatestVersionBadAddress(t *testing.T) { + ver, err := GetLatestVersion("a.super.non.existent.domain/dapr/dapr") + assert.Error(t, err) + assert.Empty(t, ver) +} +func TestDaprImageRef(t *testing.T) { tests := []struct { - Name string - Path string - ResponseBody string - ExpectedErr string - ExpectedVer string + name string + imageRegistryURL string + expected string }{ { - "Use RC releases if there isn't a full release yet", - "/fallback_to_rc", - `apiVersion: v1 -entries: - dapr: - - apiVersion: v1 - appVersion: 1.2.3-rc.1 - created: "2021-06-17T03:13:24.179849371Z" - description: A Helm chart for Dapr on Kubernetes - digest: 60d8d17b58ca316cdcbdb8529cf9ba2c9e2e0834383c677cafbf99add86ee7a0 - name: dapr - urls: - - https://dapr.github.io/helm-charts/dapr-1.2.3-rc.1.tgz - version: 1.2.3-rc.1 - - apiVersion: v1 - appVersion: 1.2.2 - created: "2021-06-17T03:13:24.179849371Z" - description: A Helm chart for Dapr on Kubernetes - digest: 60d8d17b58ca316cdcbdb8529cf9ba2c9e2e0834383c677cafbf99add86ee7a0 - name: dapr - urls: - - https://dapr.github.io/helm-charts/dapr-1.2.2.tgz - version: 1.2.2 `, - "", - "1.2.2", - }, - { - "Malformed YAML", - "/malformed", - "[", - "yaml: line 1: did not find expected node content", - "", + name: "custom registry", + imageRegistryURL: "localhost:5000", + expected: "localhost:5000/dapr/dapr", }, { - "Empty YAML", - "/empty", - "", - "no releases", - "", + name: "default Docker Hub", + expected: DaprDefaultImage, }, { - "Only RCs", - "/only_rcs", - `apiVersion: v1 -entries: - dapr: - - apiVersion: v1 - appVersion: 1.2.3-rc.1 - created: "2021-06-17T03:13:24.179849371Z" - description: A Helm chart for Dapr on Kubernetes - digest: 60d8d17b58ca316cdcbdb8529cf9ba2c9e2e0834383c677cafbf99add86ee7a0 - name: dapr - urls: - - https://dapr.github.io/helm-charts/dapr-1.2.3-rc.1.tgz - version: 1.2.3-rc.1 `, - "", - "1.2.3-rc.1", + name: "default Docker Hub, empty registry URL", + imageRegistryURL: "", + expected: DaprDefaultImage, }, } - m := http.NewServeMux() - s := http.Server{Addr: ":12346", Handler: m, ReadHeaderTimeout: time.Duration(5) * time.Second} for _, tc := range tests { - body := tc.ResponseBody - m.HandleFunc(tc.Path, func(w http.ResponseWriter, r *http.Request) { - fmt.Fprint(w, body) + t.Run(tc.name, func(t *testing.T) { + result := DaprImageRef(tc.imageRegistryURL) + assert.Equal(t, tc.expected, result) }) } +} - go func() { - s.ListenAndServe() - }() +func TestDashboardImageRef(t *testing.T) { + tests := []struct { + name string + imageRegistryURL string + expected string + }{ + { + name: "custom registry", + imageRegistryURL: "localhost:5000", + expected: "localhost:5000/dapr/dashboard", + }, + { + name: "default Docker Hub", + expected: DashboardDefaultImage, + }, + { + name: "default Docker Hub, empty registry URL", + imageRegistryURL: "", + expected: DashboardDefaultImage, + }, + } for _, tc := range tests { - t.Run(tc.Name, func(t *testing.T) { - version, err := GetLatestReleaseHelmChart("http://localhost:12346" + tc.Path) - assert.Equal(t, tc.ExpectedVer, version) - if tc.ExpectedErr != "" { - assert.EqualError(t, err, tc.ExpectedErr) - } + t.Run(tc.name, func(t *testing.T) { + result := DashboardImageRef(tc.imageRegistryURL) + assert.Equal(t, tc.expected, result) }) } +} - s.Shutdown(t.Context()) +func TestImageRefCanBeResolved(t *testing.T) { + // Verify that the default image refs are valid repository references. + refs := []string{DaprDefaultImage, DashboardDefaultImage} + for _, ref := range refs { + t.Run(ref, func(t *testing.T) { + _, err := name.NewRepository(ref) + require.NoError(t, err, "default image ref %q should be a valid repository", ref) + }) + } } diff --git a/tests/e2e/standalone/init_test.go b/tests/e2e/standalone/init_test.go index 9f4a81e81..9f567c7de 100644 --- a/tests/e2e/standalone/init_test.go +++ b/tests/e2e/standalone/init_test.go @@ -27,7 +27,6 @@ import ( "time" "github.com/Masterminds/semver" - "github.com/dapr/cli/pkg/version" "github.com/dapr/cli/tests/e2e/common" "github.com/dapr/cli/tests/e2e/spawn" "github.com/docker/docker/api/types/container" @@ -157,10 +156,7 @@ func TestStandaloneInit(t *testing.T) { daprPath := filepath.Join(homeDir, ".dapr") require.DirExists(t, daprPath, "Directory %s does not exist", daprPath) - latestDaprRuntimeVersion, err := version.GetDaprVersion() - require.NoError(t, err) - latestDaprDashboardVersion, err := version.GetDashboardVersion() - require.NoError(t, err) + latestDaprRuntimeVersion, latestDaprDashboardVersion := common.GetVersionsFromEnv(t, true) verifyContainers(t, latestDaprRuntimeVersion) verifyBinaries(t, daprPath, latestDaprRuntimeVersion, latestDaprDashboardVersion) @@ -247,10 +243,7 @@ func TestStandaloneInit(t *testing.T) { daprPath := filepath.Join(homeDir, ".dapr") require.DirExists(t, daprPath, "Directory %s does not exist", daprPath) - latestDaprRuntimeVersion, err := version.GetDaprVersion() - require.NoError(t, err) - latestDaprDashboardVersion, err := version.GetDashboardVersion() - require.NoError(t, err) + latestDaprRuntimeVersion, latestDaprDashboardVersion := common.GetVersionsFromEnv(t, true) verifyContainers(t, latestDaprRuntimeVersion+"-mariner") verifyBinaries(t, daprPath, latestDaprRuntimeVersion, latestDaprDashboardVersion)