diff --git a/build/package/purls.txt b/build/package/purls.txt index 3f8e1893..f23570bc 100644 --- a/build/package/purls.txt +++ b/build/package/purls.txt @@ -1,17 +1,20 @@ +pkg:golang/al.essio.dev/pkg/shellescape@v1.5.1 pkg:golang/github.com/Masterminds/semver/v3@v3.4.0 pkg:golang/github.com/PaesslerAG/gval@v1.0.0 pkg:golang/github.com/PaesslerAG/jsonpath@v0.1.1 +pkg:golang/github.com/danieljoos/wincred@v1.2.2 pkg:golang/github.com/davecgh/go-spew@v1.1.2-0.20180830191138-d8f796af33cc pkg:golang/github.com/emicklei/go-restful/v3@v3.11.0 pkg:golang/github.com/evanphx/json-patch/v5@v5.9.11 -pkg:golang/github.com/fsnotify/fsnotify@v1.7.0 +pkg:golang/github.com/fsnotify/fsnotify@v1.9.0 pkg:golang/github.com/fxamacker/cbor/v2@v2.7.0 pkg:golang/github.com/go-logr/logr@v1.4.3 pkg:golang/github.com/go-openapi/jsonpointer@v0.21.0 pkg:golang/github.com/go-openapi/jsonreference@v0.20.2 pkg:golang/github.com/go-openapi/swag@v0.23.0 +pkg:golang/github.com/godbus/dbus/v5@v5.1.0 pkg:golang/github.com/gogo/protobuf@v1.3.2 -pkg:golang/github.com/golang-jwt/jwt/v4@v4.5.2 +pkg:golang/github.com/golang-jwt/jwt/v5@v5.3.0 pkg:golang/github.com/google/gnostic-models@v0.6.9 pkg:golang/github.com/google/go-cmp@v0.7.0 pkg:golang/github.com/google/go-github/v61@v61.0.0 @@ -27,7 +30,7 @@ pkg:golang/github.com/mitchellh/mapstructure@v1.5.0 pkg:golang/github.com/modern-go/concurrent@v0.0.0-20180306012644-bacd9c7ef1dd pkg:golang/github.com/modern-go/reflect2@v1.0.2 pkg:golang/github.com/mongodb-forks/digest@v1.1.0 -pkg:golang/github.com/mongodb/atlas-cli-core@v0.0.0-20250214162807-8f937b802e87 +pkg:golang/github.com/mongodb/atlas-cli-core@v0.0.0-20250827124955-3a1f456f077e pkg:golang/github.com/mongodb/mongodb-atlas-kubernetes/v2@v2.10.0 pkg:golang/github.com/munnerz/goautoneg@v0.0.0-20191010083416-a7dc8b61c822 pkg:golang/github.com/pelletier/go-toml/v2@v2.2.2 @@ -41,9 +44,11 @@ pkg:golang/github.com/spf13/viper@v1.19.0 pkg:golang/github.com/subosito/gotenv@v1.6.0 pkg:golang/github.com/tangzero/inflector@v1.0.0 pkg:golang/github.com/x448/float16@v0.8.4 +pkg:golang/github.com/zalando/go-keyring@v0.2.6 pkg:golang/go.mongodb.org/atlas-sdk/v20240530005@v20240530005.0.0 pkg:golang/go.mongodb.org/atlas-sdk/v20241113004@v20241113004.0.0 pkg:golang/go.mongodb.org/atlas-sdk/v20250312002@v20250312002.0.0 +pkg:golang/go.mongodb.org/atlas-sdk/v20250312006@v20250312006.0.0 pkg:golang/go.mongodb.org/atlas@v0.38.0 pkg:golang/go.uber.org/multierr@v1.11.0 pkg:golang/go.uber.org/zap@v1.27.0 @@ -51,7 +56,7 @@ pkg:golang/go.yaml.in/yaml/v2@v2.4.2 pkg:golang/golang.org/x/exp@v0.0.0-20240719175910-8a7402abbf56 pkg:golang/golang.org/x/net@v0.42.0 pkg:golang/golang.org/x/oauth2@v0.30.0 -pkg:golang/golang.org/x/sys@v0.34.0 +pkg:golang/golang.org/x/sys@v0.35.0 pkg:golang/golang.org/x/term@v0.33.0 pkg:golang/golang.org/x/text@v0.27.0 pkg:golang/golang.org/x/time@v0.12.0 diff --git a/go.mod b/go.mod index dda25069..30b68a8d 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,8 @@ module github.com/mongodb/atlas-cli-plugin-kubernetes -go 1.24.0 +go 1.24.2 -toolchain go1.24.1 +toolchain go1.24.6 require ( cloud.google.com/go/compute v1.44.0 @@ -15,9 +15,8 @@ require ( github.com/golang/mock v1.6.0 github.com/google/go-github/v61 v61.0.0 github.com/google/uuid v1.6.0 - github.com/mongodb-forks/digest v1.1.0 github.com/mongodb-labs/cobra2snooty v1.19.1 - github.com/mongodb/atlas-cli-core v0.0.0-20250214162807-8f937b802e87 + github.com/mongodb/atlas-cli-core v0.0.0-20250827124955-3a1f456f077e github.com/mongodb/mongodb-atlas-kubernetes/v2 v2.10.0 github.com/spf13/afero v1.14.0 github.com/spf13/cobra v1.9.1 @@ -50,19 +49,20 @@ require ( github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect github.com/BurntSushi/toml v1.4.0 // indirect github.com/PaesslerAG/gval v1.0.0 // indirect + github.com/danieljoos/wincred v1.2.2 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/evanphx/json-patch/v5 v5.9.11 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.23.0 // indirect + github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang-jwt/jwt/v4 v4.5.2 // indirect github.com/golang-jwt/jwt/v5 v5.3.0 // indirect github.com/google/gnostic-models v0.6.9 // indirect github.com/google/go-cmp v0.7.0 // indirect @@ -82,6 +82,7 @@ require ( github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/mongodb-forks/digest v1.1.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect @@ -95,7 +96,9 @@ require ( github.com/spf13/viper v1.19.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/x448/float16 v0.8.4 // indirect + github.com/zalando/go-keyring v0.2.6 // indirect go.mongodb.org/atlas-sdk/v20250312002 v20250312002.0.0 // indirect + go.mongodb.org/atlas-sdk/v20250312006 v20250312006.0.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect go.opentelemetry.io/otel v1.36.0 // indirect @@ -108,7 +111,7 @@ require ( golang.org/x/crypto v0.40.0 // indirect golang.org/x/net v0.42.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect - golang.org/x/sys v0.34.0 // indirect + golang.org/x/sys v0.35.0 // indirect golang.org/x/term v0.33.0 // indirect golang.org/x/text v0.27.0 // indirect golang.org/x/time v0.12.0 // indirect diff --git a/go.sum b/go.sum index 2116147f..d5ed8b9d 100644 --- a/go.sum +++ b/go.sum @@ -54,6 +54,8 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/danieljoos/wincred v1.2.2 h1:774zMFJrqaeYCK2W57BgAem/MLi6mtSE47MB6BOJ0i0= +github.com/danieljoos/wincred v1.2.2/go.mod h1:w7w4Utbrz8lqeMbDAK0lkNJUv5sAOkFi7nd/ogr0Uh8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -66,8 +68,8 @@ github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2 github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= -github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= -github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -89,10 +91,10 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= -github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= @@ -168,8 +170,8 @@ github.com/mongodb-forks/digest v1.1.0 h1:7eUdsR1BtqLv0mdNm4OXs6ddWvR4X2/OsLwdKk github.com/mongodb-forks/digest v1.1.0/go.mod h1:rb+EX8zotClD5Dj4NdgxnJXG9nwrlx3NWKJ8xttz1Dg= github.com/mongodb-labs/cobra2snooty v1.19.1 h1:GDEQZWy8f/DeJlImNgVvStu6sgNi8nuSOR1Oskcw8BI= github.com/mongodb-labs/cobra2snooty v1.19.1/go.mod h1:Hyq4YadN8dwdOiz56MXwTuVN63p0WlkQwxdLxOSGdX8= -github.com/mongodb/atlas-cli-core v0.0.0-20250214162807-8f937b802e87 h1:Y9Gh8mkiHbDE7pXPWprLgNo0onWLtrQe25sTfqvlS5c= -github.com/mongodb/atlas-cli-core v0.0.0-20250214162807-8f937b802e87/go.mod h1:zeBvF+hvzhmHwvjT9QuLeGrKQlsY1YlQo8v25wWzQug= +github.com/mongodb/atlas-cli-core v0.0.0-20250827124955-3a1f456f077e h1:NOpLvS5NRJE5AuN0pVezCHOheXzYKTH0tOnDHNknZiw= +github.com/mongodb/atlas-cli-core v0.0.0-20250827124955-3a1f456f077e/go.mod h1:QDfVGpdfxXM1httLNXCKsfWTKv6slzCqBZxkkPIktlQ= github.com/mongodb/mongodb-atlas-kubernetes/v2 v2.10.0 h1:6vJu9bj6MLnF3Vp4Zo4jQcgbuzO69IUmY3MRT3oCtAw= github.com/mongodb/mongodb-atlas-kubernetes/v2 v2.10.0/go.mod h1:SaiLtnWefhrHd0rqBJosYuyn7kJ7pImY4Jqtna5hl7s= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= @@ -242,6 +244,8 @@ github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcY github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/zalando/go-keyring v0.2.6 h1:r7Yc3+H+Ux0+M72zacZoItR3UDxeWfKTcabvkI8ua9s= +github.com/zalando/go-keyring v0.2.6/go.mod h1:2TCrxYrbUNYfNS/Kgy/LSrkSQzZ5UPVH85RwfczwvcI= go.mongodb.org/atlas v0.38.0 h1:zfwymq20GqivGwxPZfypfUDry+WwMGVui97z1d8V4bU= go.mongodb.org/atlas v0.38.0/go.mod h1:DJYtM+vsEpPEMSkQzJnFHrT0sP7ev6cseZc/GGjJYG8= go.mongodb.org/atlas-sdk/v20240530005 v20240530005.0.0 h1:d/gbYJ+obR0EM/3DZf7+ZMi2QWISegm3mid7Or708cc= @@ -252,6 +256,8 @@ go.mongodb.org/atlas-sdk/v20250219001 v20250219001.1.0 h1:tm7d3xvbNFIpuvFcppXc1z go.mongodb.org/atlas-sdk/v20250219001 v20250219001.1.0/go.mod h1:huR1gWJhExa60NIRhsLDdc7RmmqKJJwnbdlA1UUh8V4= go.mongodb.org/atlas-sdk/v20250312002 v20250312002.0.0 h1:KX8PrYp3/PCSxG4NbGLcc3+EsNcfyhcvylGbe/oRlx8= go.mongodb.org/atlas-sdk/v20250312002 v20250312002.0.0/go.mod h1:HHCmHxHPdJRr1bUXlvRIZbm7M4gRujjur1GnjE44YgA= +go.mongodb.org/atlas-sdk/v20250312006 v20250312006.0.0 h1:3y9pfi0UYVTz/44lhtVQkvDWg/QMB+jOoxA7poab1nU= +go.mongodb.org/atlas-sdk/v20250312006 v20250312006.0.0/go.mod h1:UZYSaCimjGs3j+wMwgHSKUSIvoJXzmy/xrer0t5TLgo= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus= @@ -270,6 +276,8 @@ go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= +go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= @@ -311,8 +319,8 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= -golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= +golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= @@ -327,8 +335,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= -golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= +golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg= +golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s= 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/internal/cli/kubernetes/kubernetes.go b/internal/cli/kubernetes/kubernetes.go index 8f638f10..8c2a08de 100644 --- a/internal/cli/kubernetes/kubernetes.go +++ b/internal/cli/kubernetes/kubernetes.go @@ -33,8 +33,8 @@ import ( func Builder() *cobra.Command { const use = "kubernetes" var ( - profile string - debugLevel bool + profileName string + debugLevel bool ) cmd := &cobra.Command{ @@ -47,11 +47,14 @@ func Builder() *cobra.Command { log.SetLevel(log.DebugLevel) } - err := coreConfig.LoadAtlasCLIConfig() + profile, err := coreConfig.LoadAtlasCLIConfig() if err != nil { return fmt.Errorf("failed to load Atlas CLI configuration: %v", err) } - if err := coreConfig.InitProfile(profile); err != nil { + + coreConfig.WithProfile(cmd.Context(), profile) + + if err := coreConfig.InitProfile(profileName); err != nil { return fmt.Errorf("failed to initialise Atlas CLI profile: %w", err) } @@ -62,7 +65,7 @@ func Builder() *cobra.Command { cmd.AddCommand(config.Builder(), operator.Builder(), dryrun.Builder()) - cmd.PersistentFlags().StringVarP(&profile, flag.Profile, flag.ProfileShort, "", usage.ProfileAtlasCLI) + cmd.PersistentFlags().StringVarP(&profileName, flag.Profile, flag.ProfileShort, "", usage.ProfileAtlasCLI) cmd.PersistentFlags().BoolVarP(&debugLevel, flag.Debug, flag.DebugShort, false, usage.Debug) _ = cmd.PersistentFlags().MarkHidden(flag.Debug) diff --git a/internal/mocks/mock_store.go b/internal/mocks/mock_store.go index 9d0c8a5f..8ae95d83 100644 --- a/internal/mocks/mock_store.go +++ b/internal/mocks/mock_store.go @@ -49,6 +49,34 @@ func (mr *MockCredentialsGetterMockRecorder) AuthType() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AuthType", reflect.TypeOf((*MockCredentialsGetter)(nil).AuthType)) } +// ClientID mocks base method. +func (m *MockCredentialsGetter) ClientID() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClientID") + ret0, _ := ret[0].(string) + return ret0 +} + +// ClientID indicates an expected call of ClientID. +func (mr *MockCredentialsGetterMockRecorder) ClientID() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClientID", reflect.TypeOf((*MockCredentialsGetter)(nil).ClientID)) +} + +// ClientSecret mocks base method. +func (m *MockCredentialsGetter) ClientSecret() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClientSecret") + ret0, _ := ret[0].(string) + return ret0 +} + +// ClientSecret indicates an expected call of ClientSecret. +func (mr *MockCredentialsGetterMockRecorder) ClientSecret() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClientSecret", reflect.TypeOf((*MockCredentialsGetter)(nil).ClientSecret)) +} + // PrivateAPIKey mocks base method. func (m *MockCredentialsGetter) PrivateAPIKey() string { m.ctrl.T.Helper() diff --git a/internal/store/store.go b/internal/store/store.go index 19584adb..c4389832 100644 --- a/internal/store/store.go +++ b/internal/store/store.go @@ -24,8 +24,8 @@ import ( "strings" "github.com/mongodb/atlas-cli-core/config" + "github.com/mongodb/atlas-cli-core/transport" "github.com/mongodb/atlas-cli-plugin-kubernetes/internal/log" - "github.com/mongodb/atlas-cli-plugin-kubernetes/internal/transport" "github.com/mongodb/atlas-cli-plugin-kubernetes/internal/version" atlasClustersPinned "go.mongodb.org/atlas-sdk/v20240530005/admin" atlasv2 "go.mongodb.org/atlas-sdk/v20241113004/admin" @@ -44,13 +44,11 @@ const ( var errUnsupportedService = errors.New("unsupported service") type Store struct { - service string - baseURL string - telemetry bool - username string - password string - accessToken *atlasauth.Token - client *atlas.Client + service string + baseURL string + telemetry bool + httpClient *http.Client + client *atlas.Client // Latest release of the autogenerated Atlas V2 API Client clientv2 *atlasv2.APIClient // Pinnned version to the most recent version that's working for clusters @@ -58,18 +56,32 @@ type Store struct { ctx context.Context } -func (s *Store) httpClient(httpTransport http.RoundTripper) (*http.Client, error) { - if s.username != "" && s.password != "" { - t := transport.NewDigestTransport(s.username, s.password, httpTransport) +func HttpClient(c CredentialsGetter, httpTransport http.RoundTripper) (*http.Client, error) { + switch c.AuthType() { + case config.APIKeys: + t := transport.NewDigestTransport(c.PublicAPIKey(), c.PrivateAPIKey(), httpTransport) return t.Client() - } - if s.accessToken != nil { - tr := transport.NewAccessTokenTransport(s.accessToken, httpTransport) - + case config.UserAccount: + token, err := c.Token() + if err != nil { + return nil, err + } + tr, err := transport.NewAccessTokenTransport(token, httpTransport, version.Version, func(t *atlasauth.Token) error { + config.SetAccessToken(t.AccessToken) + config.SetRefreshToken(t.RefreshToken) + return config.Save() + }) + if err != nil { + return nil, err + } return &http.Client{Transport: tr}, nil + case config.ServiceAccount: + return transport.NewServiceAccountClientWithHost(c.ClientID(), c.ClientSecret(), config.OpsManagerURL()), nil + case config.NoAuth: + fallthrough + default: + return &http.Client{Transport: httpTransport}, nil } - - return &http.Client{Transport: httpTransport}, nil } func (s *Store) transport() *http.Transport { @@ -121,6 +133,8 @@ func WithBaseURL(configURL string) Option { type CredentialsGetter interface { PublicAPIKey() string PrivateAPIKey() string + ClientID() string + ClientSecret() string Token() (*atlasauth.Token, error) AuthType() config.AuthMechanism } @@ -128,16 +142,11 @@ type CredentialsGetter interface { // WithAuthentication sets the store credentials. func WithAuthentication(c CredentialsGetter) Option { return func(s *Store) error { - s.username = c.PublicAPIKey() - s.password = c.PrivateAPIKey() - - if s.username == "" && s.password == "" { - t, err := c.Token() - if err != nil { - return err - } - s.accessToken = t + client, err := HttpClient(c, s.transport()) + if err != nil { + return err } + s.httpClient = client return nil } } @@ -151,7 +160,7 @@ func WithContext(ctx context.Context) Option { } // setAtlasClient sets the internal client to use an Atlas client and methods. -func (s *Store) setAtlasClient(client *http.Client) error { +func (s *Store) setAtlasClient() error { opts := []atlas.ClientOpt{atlas.SetUserAgent(config.UserAgent(version.Version))} if s.baseURL != "" { opts = append(opts, atlas.SetBaseURL(s.baseURL)) @@ -159,17 +168,17 @@ func (s *Store) setAtlasClient(client *http.Client) error { if log.IsDebugLevel() { opts = append(opts, atlas.SetWithRaw()) } - c, err := atlas.New(client, opts...) + c, err := atlas.New(s.httpClient, opts...) if err != nil { return err } - err = s.createV2Client(client) + err = s.createV2Client(s.httpClient) if err != nil { return err } - err = s.createClustersClient(client) + err = s.createClustersClient(s.httpClient) if err != nil { return err } @@ -281,11 +290,7 @@ func New(opts ...Option) (*Store, error) { } } - client, err := store.httpClient(store.transport()) - if err != nil { - return nil, err - } - if err = store.setAtlasClient(client); err != nil { + if err := store.setAtlasClient(); err != nil { return nil, err } diff --git a/internal/store/store_test.go b/internal/store/store_test.go index 76d22d43..4c435dc9 100644 --- a/internal/store/store_test.go +++ b/internal/store/store_test.go @@ -1,10 +1,10 @@ -// Copyright 2020 MongoDB Inc +// Copyright 2025 MongoDB Inc // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -21,21 +21,25 @@ import ( "testing" "github.com/mongodb/atlas-cli-core/config" + "github.com/stretchr/testify/require" atlasauth "go.mongodb.org/atlas/auth" ) type auth struct { - username string - password string - token string + username string + password string + refreshToken string + clientID string + clientSecret string + accessToken *atlasauth.Token } -func (auth) Token() (*atlasauth.Token, error) { - return nil, nil +func (a auth) Token() (*atlasauth.Token, error) { + return a.accessToken, nil } func (a auth) RefreshToken() string { - return a.token + return a.refreshToken } func (a auth) PublicAPIKey() string { @@ -46,14 +50,25 @@ func (a auth) PrivateAPIKey() string { return a.password } +func (a auth) ClientID() string { + return a.clientID +} + +func (a auth) ClientSecret() string { + return a.clientSecret +} + func (a auth) AuthType() config.AuthMechanism { if a.username != "" { return config.APIKeys } - if a.token != "" { - return config.OAuth + if a.accessToken != nil { + return config.UserAccount + } + if a.clientID != "" { + return config.ServiceAccount } - return config.NotLoggedIn + return "" } var _ CredentialsGetter = &auth{} @@ -104,21 +119,44 @@ func (c testConfig) OpsManagerURL() string { var _ AuthenticatedConfig = &testConfig{} func TestWithAuthentication(t *testing.T) { - a := auth{ - username: "username", - password: "password", + tests := []struct { + name string + a auth + }{ + { + name: "api keys", + a: auth{ + username: "username", + password: "password", + }, + }, + { + name: "service account", + a: auth{ + clientID: "id", + clientSecret: "secret", + }, + }, + { + name: "user account", + a: auth{ + refreshToken: "token", + accessToken: &atlasauth.Token{ + AccessToken: "access", + RefreshToken: "refresh", + }, + }, + }, } - c, err := New(Service("cloud"), WithAuthentication(a)) - if err != nil { - t.Fatalf("New() unexpected error: %v", err) - } - - if c.username != a.username { - t.Errorf("New() username = %s; expected %s", c.username, a.username) - } - if c.password != a.password { - t.Errorf("New() password = %s; expected %s", c.password, a.password) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c, err := New(Service("cloud"), WithAuthentication(tt.a)) + require.NoError(t, err) + require.NotNil(t, c.httpClient) + require.NotNil(t, c.httpClient.Transport) + require.NotEqual(t, c.transport(), c.httpClient.Transport) // Check transport is not default + }) } } @@ -128,14 +166,14 @@ func TestWithContext(t *testing.T) { t.Fatalf("New() unexpected error: %v", err) } - if c.ctx != context.Background() { - t.Errorf("New() got %v; expected %v", c.ctx, context.Background()) + if c.ctx != context.Background() { //nolint: usetesting // we test this value + t.Errorf("New() got %v; expected %v", c.ctx, t.Context()) } type myCustomType string var k, v myCustomType = "custom key", "custom value" - ctx := context.WithValue(context.Background(), k, v) + ctx := context.WithValue(t.Context(), k, v) c, err = New(Service(config.CloudService), WithContext(ctx)) if err != nil { diff --git a/internal/transport/transport.go b/internal/transport/transport.go deleted file mode 100644 index 2da5e908..00000000 --- a/internal/transport/transport.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2024 MongoDB Inc -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package transport - -import ( - "net" - "net/http" - "time" - - "github.com/mongodb-forks/digest" - atlasauth "go.mongodb.org/atlas/auth" -) - -const ( - telemetryTimeout = 1 * time.Second - timeout = 5 * time.Second - keepAlive = 30 * time.Second - maxIdleConns = 5 - maxIdleConnsPerHost = 4 - idleConnTimeout = 30 * time.Second - expectContinueTimeout = 1 * time.Second -) - -var defaultTransport = newTransport(timeout) - -func Default() *http.Transport { - return defaultTransport -} - -var telemetryTransport = newTransport(telemetryTimeout) - -func Telemetry() *http.Transport { - return telemetryTransport -} - -func newTransport(timeout time.Duration) *http.Transport { - return &http.Transport{ - DialContext: (&net.Dialer{ - Timeout: timeout, - KeepAlive: keepAlive, - }).DialContext, - MaxIdleConns: maxIdleConns, - MaxIdleConnsPerHost: maxIdleConnsPerHost, - Proxy: http.ProxyFromEnvironment, - IdleConnTimeout: idleConnTimeout, - ExpectContinueTimeout: expectContinueTimeout, - } -} - -func NewDigestTransport(username, password string, base http.RoundTripper) *digest.Transport { - return &digest.Transport{ - Username: username, - Password: password, - Transport: base, - } -} - -func NewAccessTokenTransport(token *atlasauth.Token, base http.RoundTripper) http.RoundTripper { - return &tokenTransport{ - token: token, - base: base, - } -} - -type tokenTransport struct { - token *atlasauth.Token - base http.RoundTripper -} - -func (tr *tokenTransport) RoundTrip(req *http.Request) (*http.Response, error) { - tr.token.SetAuthHeader(req) - return tr.base.RoundTrip(req) -} diff --git a/test/e2e/kubernetes_operator_install_test.go b/test/e2e/kubernetes_operator_install_test.go index fb44ceb7..fd5aa80b 100644 --- a/test/e2e/kubernetes_operator_install_test.go +++ b/test/e2e/kubernetes_operator_install_test.go @@ -58,7 +58,7 @@ func TestKubernetesOperatorInstall(t *testing.T) { cmd.Env = os.Environ() _, inErr := test.RunAndGetStdOutAndErr(cmd) require.Error(t, inErr) - assert.Equal(t, "Error: version 1.1.0 is not supported\n (exit status 1)", inErr.Error()) + assert.Contains(t, inErr.Error(), "Error: version 1.1.0 is not supported") }) t.Run("should failed to install a non-existing version of the operator", func(t *testing.T) { @@ -70,7 +70,7 @@ func TestKubernetesOperatorInstall(t *testing.T) { cmd.Env = os.Environ() _, inErr := test.RunAndGetStdOutAndErr(cmd) require.Error(t, inErr) - assert.Equal(t, "Error: version 100.0.0 is not supported\n (exit status 1)", inErr.Error()) + assert.Contains(t, inErr.Error(), "Error: version 100.0.0 is not supported") }) t.Run("should failed when unable to setup connection to the cluster", func(t *testing.T) { @@ -82,7 +82,7 @@ func TestKubernetesOperatorInstall(t *testing.T) { cmd.Env = os.Environ() _, inErr := test.RunAndGetStdOutAndErr(cmd) require.Error(t, inErr) - assert.Equal(t, "Error: unable to prepare client configuration: invalid configuration: no configuration has been provided, try setting KUBERNETES_MASTER environment variable\n (exit status 1)", inErr.Error()) + assert.Contains(t, inErr.Error(), "Error: unable to prepare client configuration: invalid configuration: no configuration has been provided, try setting KUBERNETES_MASTER environment variable") }) t.Run("should only install operator configuration", func(t *testing.T) { @@ -117,7 +117,7 @@ func TestKubernetesOperatorInstall(t *testing.T) { cmd.Env = os.Environ() resp, inErr := test.RunAndGetStdOutAndErr(cmd) require.NoError(t, inErr) - assert.Equal(t, "Atlas Kubernetes Operator installed successfully\n", string(resp)) + assert.Contains(t, string(resp), "Atlas Kubernetes Operator installed successfully") checkDeployment(t, operator, "default") }) @@ -136,7 +136,7 @@ func TestKubernetesOperatorInstall(t *testing.T) { cmd.Env = os.Environ() resp, err := cmd.CombinedOutput() require.NoError(t, err, string(resp)) - assert.Equal(t, "Atlas Kubernetes Operator installed successfully\n", string(resp)) + assert.Contains(t, string(resp), "Atlas Kubernetes Operator installed successfully") checkDeployment(t, operator, operatorNamespace) }) @@ -159,7 +159,7 @@ func TestKubernetesOperatorInstall(t *testing.T) { cmd.Env = os.Environ() resp, err := cmd.CombinedOutput() require.NoError(t, err, string(resp)) - assert.Equal(t, "Atlas Kubernetes Operator installed successfully\n", string(resp)) + assert.Contains(t, string(resp), "Atlas Kubernetes Operator installed successfully") checkDeployment(t, operator, operatorNamespace) }) @@ -178,7 +178,7 @@ func TestKubernetesOperatorInstall(t *testing.T) { cmd.Env = os.Environ() resp, err := cmd.CombinedOutput() require.NoError(t, err, string(resp)) - assert.Equal(t, "Atlas Kubernetes Operator installed successfully\n", string(resp)) + assert.Contains(t, string(resp), "Atlas Kubernetes Operator installed successfully") checkDeployment(t, operator, operatorNamespace) }) @@ -200,7 +200,7 @@ func TestKubernetesOperatorInstall(t *testing.T) { cmd.Env = os.Environ() resp, err := cmd.CombinedOutput() require.NoError(t, err, string(resp)) - assert.Equal(t, "Atlas Kubernetes Operator installed successfully\n", string(resp)) + assert.Contains(t, string(resp), "Atlas Kubernetes Operator installed successfully") checkDeployment(t, operator, operatorNamespace) @@ -275,7 +275,7 @@ func TestKubernetesOperatorInstall(t *testing.T) { cmd.Env = os.Environ() resp, err := cmd.CombinedOutput() require.NoError(t, err, string(resp)) - assert.Equal(t, "Atlas Kubernetes Operator installed successfully\n", string(resp)) + assert.Contains(t, string(resp), "Atlas Kubernetes Operator installed successfully") checkDeployment(t, operator, operatorNamespace) checkK8sAtlasProject(t, operator, client.ObjectKey{Name: prepareK8sName(g.projectName), Namespace: operatorNamespace}) @@ -305,7 +305,7 @@ func TestKubernetesOperatorInstall(t *testing.T) { cmd.Env = os.Environ() resp, err := cmd.CombinedOutput() require.NoError(t, err, string(resp)) - assert.Equal(t, "Atlas Kubernetes Operator installed successfully\n", string(resp)) + assert.Contains(t, string(resp), "Atlas Kubernetes Operator installed successfully") checkDeployment(t, operator, operatorNamespace)