From bab937c88fbbaff1052dc0e0e68fa3108abe79e5 Mon Sep 17 00:00:00 2001 From: Maxence Maireaux Date: Thu, 12 Mar 2026 11:40:24 +0100 Subject: [PATCH 1/6] feat: Update go-libs v2 to v4 --- api/formance.com/v1beta1/shared.go | 2 +- go.mod | 22 +++--- go.sum | 72 ++++++++++------- internal/core/env.go | 2 +- internal/core/reconciler.go | 2 +- internal/core/setup.go | 2 +- internal/core/utils.go | 2 +- .../resources/applications/application.go | 2 +- internal/resources/auths/configuration.go | 2 +- internal/resources/auths/deployment.go | 2 +- internal/resources/auths/init.go | 2 +- internal/resources/benthos/controller.go | 2 +- .../resources/brokerconsumers/controller.go | 2 +- internal/resources/brokerconsumers/create.go | 2 +- internal/resources/brokers/reconcile.go | 2 +- internal/resources/brokers/utils.go | 2 +- internal/resources/caddy/caddy.go | 2 +- internal/resources/databases/init.go | 2 +- internal/resources/gateways/caddyfile.go | 2 +- internal/resources/gateways/init.go | 2 +- internal/resources/jobs/job.go | 2 +- internal/resources/ledgers/reindex.go | 2 +- internal/resources/resourcereferences/init.go | 2 +- internal/resources/services/services_test.go | 2 +- internal/resources/settings/helpers.go | 2 +- internal/resources/settings/helpers_test.go | 2 +- .../settings/resourcerequirements.go | 2 +- internal/resources/stacks/init.go | 2 +- .../tests/internal/matcher_be_owned_by.go | 2 +- tools/kubectl-stacks/go.mod | 18 ++--- tools/kubectl-stacks/go.sum | 52 ++++++------- tools/kubectl-stacks/list.go | 2 +- tools/utils/cmd/database-create.go | 4 +- tools/utils/cmd/database-drop.go | 4 +- tools/utils/cmd/database.go | 2 +- tools/utils/cmd/root.go | 4 +- tools/utils/go.mod | 3 +- tools/utils/go.sum | 78 +++++++++++-------- tools/utils/main.go | 2 +- 39 files changed, 176 insertions(+), 141 deletions(-) diff --git a/api/formance.com/v1beta1/shared.go b/api/formance.com/v1beta1/shared.go index 4c410725..de12a121 100644 --- a/api/formance.com/v1beta1/shared.go +++ b/api/formance.com/v1beta1/shared.go @@ -11,7 +11,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/formancehq/go-libs/v2/pointer" + "github.com/formancehq/go-libs/v4/pointer" ) // +kubebuilder:object:generate=false diff --git a/go.mod b/go.mod index 59fb8e7c..6a3722d4 100644 --- a/go.mod +++ b/go.mod @@ -5,18 +5,18 @@ go 1.25 toolchain go1.25.5 require ( - github.com/formancehq/go-libs/v2 v2.2.3 + github.com/formancehq/go-libs/v4 v4.1.0 github.com/go-logr/logr v1.4.3 github.com/google/go-cmp v0.7.0 github.com/google/uuid v1.6.0 github.com/iancoleman/strcase v0.3.0 github.com/imdario/mergo v0.3.16 - github.com/onsi/ginkgo/v2 v2.23.4 - github.com/onsi/gomega v1.38.0 + github.com/onsi/ginkgo/v2 v2.27.4 + github.com/onsi/gomega v1.38.2 github.com/pkg/errors v0.9.1 github.com/stoewer/go-strcase v1.3.0 github.com/stretchr/testify v1.11.1 - golang.org/x/mod v0.29.0 + golang.org/x/mod v0.31.0 gopkg.in/yaml.v3 v3.0.1 k8s.io/api v0.34.2 k8s.io/apiextensions-apiserver v0.34.1 @@ -33,13 +33,13 @@ require ( github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/google/btree v1.1.3 // indirect github.com/x448/float16 v0.8.4 // indirect - go.uber.org/automaxprocs v1.6.0 // indirect - golang.org/x/sync v0.18.0 // indirect + golang.org/x/sync v0.19.0 // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect sigs.k8s.io/randfill v1.0.0 // indirect ) require ( + github.com/Masterminds/semver/v3 v3.4.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect @@ -71,13 +71,13 @@ require ( go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/net v0.47.0 // indirect + golang.org/x/net v0.48.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/term v0.37.0 // indirect - golang.org/x/text v0.31.0 // indirect + golang.org/x/sys v0.40.0 // indirect + golang.org/x/term v0.38.0 // indirect + golang.org/x/text v0.33.0 // indirect golang.org/x/time v0.14.0 // indirect - golang.org/x/tools v0.38.0 // indirect + golang.org/x/tools v0.40.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/go.sum b/go.sum index 45c3330d..8de0948e 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= +github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= 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/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= @@ -12,12 +14,18 @@ github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= -github.com/formancehq/go-libs/v2 v2.2.3 h1:7irBJ4NfSkJdVKxXPktqVAoQa7hJcejmrXgjdgh27Zk= -github.com/formancehq/go-libs/v2 v2.2.3/go.mod h1:JvBjEDWNf7izCy2dq/eI3aMc9d28gChBe1rjw5yYlAs= +github.com/formancehq/go-libs/v4 v4.1.0 h1:DZZYTrAG31wGBKa2VpU1/Ou2fQa1F6AZKsfdMR/166Q= +github.com/formancehq/go-libs/v4 v4.1.0/go.mod h1:iVE2pTLa4KNhqXkCpBAGzpGO8TdHTEjdJMAiCkkeb0A= 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.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/gkampitakis/ciinfo v0.3.2 h1:JcuOPk8ZU7nZQjdUhctuhQofk7BGHuIy0c9Ez8BNhXs= +github.com/gkampitakis/ciinfo v0.3.2/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo= +github.com/gkampitakis/go-diff v1.3.2 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZdC4M= +github.com/gkampitakis/go-diff v1.3.2/go.mod h1:LLgOrpqleQe26cte8s36HTWcTmMEur6OPYerdAAS9tk= +github.com/gkampitakis/go-snaps v0.5.15 h1:amyJrvM1D33cPHwVrjo9jQxX8g/7E2wYdZ+01KS3zGE= +github.com/gkampitakis/go-snaps v0.5.15/go.mod h1:HNpx/9GoKisdhw9AFOBT1N7DBs9DiHo/hGheFGBZ+mc= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= @@ -30,6 +38,8 @@ github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZ github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= +github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= @@ -51,12 +61,14 @@ github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/joshdk/go-junit v1.0.0 h1:S86cUKIdwBHWwA6xCmFlf3RTLfVXYQfvanM5Uh+K6GE= +github.com/joshdk/go-junit v1.0.0/go.mod h1:TiiV0PqkaNfFXjEiyjWM3XXrhVyCa1K4Zfga6W52ung= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= -github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw= +github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -65,6 +77,10 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= +github.com/maruel/natural v1.1.1 h1:Hja7XhhmvEFhcByqDoHz9QZbkWey+COd9xWfCfn1ioo= +github.com/maruel/natural v1.1.1/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg= +github.com/mfridman/tparse v0.18.0 h1:wh6dzOKaIwkUGyKgOntDW4liXSo37qg5AXbIhkMV3vE= +github.com/mfridman/tparse v0.18.0/go.mod h1:gEvqZTuCgEhPbYk/2lS3Kcxg1GmTxxU7kTC8DvP0i/A= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -73,17 +89,15 @@ github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFd github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus= -github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8= -github.com/onsi/gomega v1.38.0 h1:c/WX+w8SLAinvuKKQFh77WEucCnPk4j2OTUr7lt7BeY= -github.com/onsi/gomega v1.38.0/go.mod h1:OcXcwId0b9QsE7Y49u+BTrL4IdKOBOKnD6VQNTJEB6o= +github.com/onsi/ginkgo/v2 v2.27.4 h1:fcEcQW/A++6aZAZQNUmNjvA9PSOzefMJBerHJ4t8v8Y= +github.com/onsi/ginkgo/v2 v2.27.4/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo= +github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A= +github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= -github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= @@ -112,12 +126,18 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= +github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= +github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= +github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= 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/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -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/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -133,41 +153,41 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 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.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= -golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= +golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= +golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= +golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= +golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 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.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= -golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= 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/core/env.go b/internal/core/env.go index 8ba81aa4..abae7ddc 100644 --- a/internal/core/env.go +++ b/internal/core/env.go @@ -5,7 +5,7 @@ import ( corev1 "k8s.io/api/core/v1" - "github.com/formancehq/go-libs/v2/collectionutils" + "github.com/formancehq/go-libs/v4/collectionutils" "github.com/formancehq/operator/v3/api/formance.com/v1beta1" ) diff --git a/internal/core/reconciler.go b/internal/core/reconciler.go index d7152546..42c2565f 100644 --- a/internal/core/reconciler.go +++ b/internal/core/reconciler.go @@ -23,7 +23,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/predicate" "sigs.k8s.io/controller-runtime/pkg/reconcile" - . "github.com/formancehq/go-libs/v2/collectionutils" + . "github.com/formancehq/go-libs/v4/collectionutils" "github.com/formancehq/operator/v3/api/formance.com/v1beta1" ) diff --git a/internal/core/setup.go b/internal/core/setup.go index 3185851f..097ee8f2 100644 --- a/internal/core/setup.go +++ b/internal/core/setup.go @@ -8,7 +8,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/formancehq/go-libs/v2/collectionutils" + "github.com/formancehq/go-libs/v4/collectionutils" "github.com/formancehq/operator/v3/api/formance.com/v1beta1" ) diff --git a/internal/core/utils.go b/internal/core/utils.go index aaa8cfd3..e082c6f2 100644 --- a/internal/core/utils.go +++ b/internal/core/utils.go @@ -23,7 +23,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/log" - "github.com/formancehq/go-libs/v2/pointer" + "github.com/formancehq/go-libs/v4/pointer" ) func HashFromConfigMaps(configMaps ...*corev1.ConfigMap) string { diff --git a/internal/resources/applications/application.go b/internal/resources/applications/application.go index 9b935125..5017ef6b 100644 --- a/internal/resources/applications/application.go +++ b/internal/resources/applications/application.go @@ -15,7 +15,7 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/formancehq/go-libs/v2/pointer" + "github.com/formancehq/go-libs/v4/pointer" "github.com/formancehq/operator/v3/api/formance.com/v1beta1" "github.com/formancehq/operator/v3/internal/core" diff --git a/internal/resources/auths/configuration.go b/internal/resources/auths/configuration.go index 31c69a1d..e399ca99 100644 --- a/internal/resources/auths/configuration.go +++ b/internal/resources/auths/configuration.go @@ -8,7 +8,7 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" - . "github.com/formancehq/go-libs/v2/collectionutils" + . "github.com/formancehq/go-libs/v4/collectionutils" "github.com/formancehq/operator/v3/api/formance.com/v1beta1" . "github.com/formancehq/operator/v3/internal/core" diff --git a/internal/resources/auths/deployment.go b/internal/resources/auths/deployment.go index 0822013f..1fc330e6 100644 --- a/internal/resources/auths/deployment.go +++ b/internal/resources/auths/deployment.go @@ -10,7 +10,7 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "github.com/formancehq/go-libs/v2/collectionutils" + "github.com/formancehq/go-libs/v4/collectionutils" "github.com/formancehq/operator/v3/api/formance.com/v1beta1" . "github.com/formancehq/operator/v3/internal/core" diff --git a/internal/resources/auths/init.go b/internal/resources/auths/init.go index d37bb7ae..fcf37b00 100644 --- a/internal/resources/auths/init.go +++ b/internal/resources/auths/init.go @@ -23,7 +23,7 @@ import ( corev1 "k8s.io/api/core/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - . "github.com/formancehq/go-libs/v2/collectionutils" + . "github.com/formancehq/go-libs/v4/collectionutils" "github.com/formancehq/operator/v3/api/formance.com/v1beta1" . "github.com/formancehq/operator/v3/internal/core" diff --git a/internal/resources/benthos/controller.go b/internal/resources/benthos/controller.go index 82ad587b..57b47d46 100644 --- a/internal/resources/benthos/controller.go +++ b/internal/resources/benthos/controller.go @@ -17,7 +17,7 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" "sigs.k8s.io/controller-runtime/pkg/client" - . "github.com/formancehq/go-libs/v2/collectionutils" + . "github.com/formancehq/go-libs/v4/collectionutils" "github.com/formancehq/operator/v3/api/formance.com/v1beta1" . "github.com/formancehq/operator/v3/internal/core" diff --git a/internal/resources/brokerconsumers/controller.go b/internal/resources/brokerconsumers/controller.go index 9209dcaf..e5956386 100644 --- a/internal/resources/brokerconsumers/controller.go +++ b/internal/resources/brokerconsumers/controller.go @@ -28,7 +28,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - "github.com/formancehq/go-libs/v2/collectionutils" + "github.com/formancehq/go-libs/v4/collectionutils" v1beta1 "github.com/formancehq/operator/v3/api/formance.com/v1beta1" "github.com/formancehq/operator/v3/internal/core" diff --git a/internal/resources/brokerconsumers/create.go b/internal/resources/brokerconsumers/create.go index b92d9d8f..bc9601e5 100644 --- a/internal/resources/brokerconsumers/create.go +++ b/internal/resources/brokerconsumers/create.go @@ -9,7 +9,7 @@ import ( "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" - . "github.com/formancehq/go-libs/v2/collectionutils" + . "github.com/formancehq/go-libs/v4/collectionutils" "github.com/formancehq/operator/v3/api/formance.com/v1beta1" "github.com/formancehq/operator/v3/internal/core" diff --git a/internal/resources/brokers/reconcile.go b/internal/resources/brokers/reconcile.go index 31b7d490..6bbb1442 100644 --- a/internal/resources/brokers/reconcile.go +++ b/internal/resources/brokers/reconcile.go @@ -11,7 +11,7 @@ import ( "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/formancehq/go-libs/v2/collectionutils" + "github.com/formancehq/go-libs/v4/collectionutils" "github.com/formancehq/operator/v3/api/formance.com/v1beta1" "github.com/formancehq/operator/v3/internal/core" diff --git a/internal/resources/brokers/utils.go b/internal/resources/brokers/utils.go index a04e9939..ac80ff87 100644 --- a/internal/resources/brokers/utils.go +++ b/internal/resources/brokers/utils.go @@ -7,7 +7,7 @@ import ( v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" - "github.com/formancehq/go-libs/v2/collectionutils" + "github.com/formancehq/go-libs/v4/collectionutils" "github.com/formancehq/operator/v3/api/formance.com/v1beta1" "github.com/formancehq/operator/v3/internal/core" diff --git a/internal/resources/caddy/caddy.go b/internal/resources/caddy/caddy.go index 14f9f0b8..b0e013a2 100644 --- a/internal/resources/caddy/caddy.go +++ b/internal/resources/caddy/caddy.go @@ -11,7 +11,7 @@ import ( v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" - "github.com/formancehq/go-libs/v2/collectionutils" + "github.com/formancehq/go-libs/v4/collectionutils" "github.com/formancehq/operator/v3/api/formance.com/v1beta1" "github.com/formancehq/operator/v3/internal/core" diff --git a/internal/resources/databases/init.go b/internal/resources/databases/init.go index 394596d5..41d58a08 100644 --- a/internal/resources/databases/init.go +++ b/internal/resources/databases/init.go @@ -26,7 +26,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/log" - "github.com/formancehq/go-libs/v2/pointer" + "github.com/formancehq/go-libs/v4/pointer" "github.com/formancehq/operator/v3/api/formance.com/v1beta1" "github.com/formancehq/operator/v3/internal/core" diff --git a/internal/resources/gateways/caddyfile.go b/internal/resources/gateways/caddyfile.go index 6f593632..916dfd26 100644 --- a/internal/resources/gateways/caddyfile.go +++ b/internal/resources/gateways/caddyfile.go @@ -3,7 +3,7 @@ package gateways import ( "strings" - "github.com/formancehq/go-libs/v2/collectionutils" + "github.com/formancehq/go-libs/v4/collectionutils" "github.com/formancehq/operator/v3/api/formance.com/v1beta1" "github.com/formancehq/operator/v3/internal/core" diff --git a/internal/resources/gateways/init.go b/internal/resources/gateways/init.go index 3c462473..2edc9c64 100644 --- a/internal/resources/gateways/init.go +++ b/internal/resources/gateways/init.go @@ -30,7 +30,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log" externaldnsv1alpha1 "sigs.k8s.io/external-dns/apis/v1alpha1" - . "github.com/formancehq/go-libs/v2/collectionutils" + . "github.com/formancehq/go-libs/v4/collectionutils" "github.com/formancehq/operator/v3/api/formance.com/v1beta1" . "github.com/formancehq/operator/v3/internal/core" diff --git a/internal/resources/jobs/job.go b/internal/resources/jobs/job.go index dcb71fe6..8d514417 100644 --- a/internal/resources/jobs/job.go +++ b/internal/resources/jobs/job.go @@ -14,7 +14,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - "github.com/formancehq/go-libs/v2/pointer" + "github.com/formancehq/go-libs/v4/pointer" "github.com/formancehq/operator/v3/api/formance.com/v1beta1" "github.com/formancehq/operator/v3/internal/core" diff --git a/internal/resources/ledgers/reindex.go b/internal/resources/ledgers/reindex.go index ada60992..389894e7 100644 --- a/internal/resources/ledgers/reindex.go +++ b/internal/resources/ledgers/reindex.go @@ -6,7 +6,7 @@ import ( "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/formancehq/go-libs/v2/pointer" + "github.com/formancehq/go-libs/v4/pointer" "github.com/formancehq/operator/v3/api/formance.com/v1beta1" "github.com/formancehq/operator/v3/internal/core" diff --git a/internal/resources/resourcereferences/init.go b/internal/resources/resourcereferences/init.go index 56841917..578a6dd9 100644 --- a/internal/resources/resourcereferences/init.go +++ b/internal/resources/resourcereferences/init.go @@ -18,7 +18,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/reconcile" - "github.com/formancehq/go-libs/v2/collectionutils" + "github.com/formancehq/go-libs/v4/collectionutils" "github.com/formancehq/operator/v3/api/formance.com/v1beta1" "github.com/formancehq/operator/v3/internal/core" diff --git a/internal/resources/services/services_test.go b/internal/resources/services/services_test.go index 82deaf07..98571ecb 100644 --- a/internal/resources/services/services_test.go +++ b/internal/resources/services/services_test.go @@ -7,7 +7,7 @@ import ( corev1 "k8s.io/api/core/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "github.com/formancehq/go-libs/v2/pointer" + "github.com/formancehq/go-libs/v4/pointer" ) func TestWithAnnotations(t *testing.T) { diff --git a/internal/resources/settings/helpers.go b/internal/resources/settings/helpers.go index e32bed78..753edd83 100644 --- a/internal/resources/settings/helpers.go +++ b/internal/resources/settings/helpers.go @@ -13,7 +13,7 @@ import ( "github.com/pkg/errors" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/formancehq/go-libs/v2/pointer" + "github.com/formancehq/go-libs/v4/pointer" "github.com/formancehq/operator/v3/api/formance.com/v1beta1" "github.com/formancehq/operator/v3/internal/core" diff --git a/internal/resources/settings/helpers_test.go b/internal/resources/settings/helpers_test.go index eae77f8e..774c1ac0 100644 --- a/internal/resources/settings/helpers_test.go +++ b/internal/resources/settings/helpers_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/require" - . "github.com/formancehq/go-libs/v2/collectionutils" + . "github.com/formancehq/go-libs/v4/collectionutils" "github.com/formancehq/operator/v3/api/formance.com/v1beta1" ) diff --git a/internal/resources/settings/resourcerequirements.go b/internal/resources/settings/resourcerequirements.go index c943fe9c..6e4490bb 100644 --- a/internal/resources/settings/resourcerequirements.go +++ b/internal/resources/settings/resourcerequirements.go @@ -4,7 +4,7 @@ import ( v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" - "github.com/formancehq/go-libs/v2/collectionutils" + "github.com/formancehq/go-libs/v4/collectionutils" "github.com/formancehq/operator/v3/internal/core" ) diff --git a/internal/resources/stacks/init.go b/internal/resources/stacks/init.go index 50c3a0ec..507c6eb1 100644 --- a/internal/resources/stacks/init.go +++ b/internal/resources/stacks/init.go @@ -25,7 +25,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/predicate" "sigs.k8s.io/controller-runtime/pkg/reconcile" - "github.com/formancehq/go-libs/v2/collectionutils" + "github.com/formancehq/go-libs/v4/collectionutils" "github.com/formancehq/operator/v3/api/formance.com/v1beta1" . "github.com/formancehq/operator/v3/internal/core" diff --git a/internal/tests/internal/matcher_be_owned_by.go b/internal/tests/internal/matcher_be_owned_by.go index 8972e7bf..8e6963e8 100644 --- a/internal/tests/internal/matcher_be_owned_by.go +++ b/internal/tests/internal/matcher_be_owned_by.go @@ -9,7 +9,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/formancehq/go-libs/v2/pointer" + "github.com/formancehq/go-libs/v4/pointer" ) type beOwnedByOption func(matcher *beOwnedByMatcher) diff --git a/tools/kubectl-stacks/go.mod b/tools/kubectl-stacks/go.mod index 6881240f..92d28826 100644 --- a/tools/kubectl-stacks/go.mod +++ b/tools/kubectl-stacks/go.mod @@ -5,7 +5,7 @@ go 1.25 toolchain go1.25.5 require ( - github.com/formancehq/go-libs/v2 v2.2.3 + github.com/formancehq/go-libs/v4 v4.1.0 github.com/formancehq/operator/v3 v3.0.0-00010101000000-000000000000 github.com/pterm/pterm v0.12.81 github.com/spf13/cobra v1.9.1 @@ -21,7 +21,7 @@ require ( atomicgo.dev/cursor v0.2.0 // indirect atomicgo.dev/keyboard v0.2.9 // indirect atomicgo.dev/schedule v0.1.0 // indirect - github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect + github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/containerd/console v1.0.5 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect @@ -47,7 +47,7 @@ require ( github.com/lithammer/fuzzysearch v1.1.8 // indirect github.com/mailru/easyjson v0.9.0 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect - github.com/moby/term v0.5.0 // indirect + github.com/moby/term v0.5.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect @@ -59,13 +59,13 @@ require ( github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/mod v0.29.0 // indirect - golang.org/x/net v0.47.0 // indirect + golang.org/x/mod v0.31.0 // indirect + golang.org/x/net v0.48.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect - golang.org/x/sync v0.18.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/term v0.37.0 // indirect - golang.org/x/text v0.31.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.40.0 // indirect + golang.org/x/term v0.38.0 // indirect + golang.org/x/text v0.33.0 // indirect golang.org/x/time v0.14.0 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect diff --git a/tools/kubectl-stacks/go.sum b/tools/kubectl-stacks/go.sum index 13a1b9b5..1124b4ed 100644 --- a/tools/kubectl-stacks/go.sum +++ b/tools/kubectl-stacks/go.sum @@ -6,8 +6,8 @@ atomicgo.dev/keyboard v0.2.9 h1:tOsIid3nlPLZ3lwgG8KZMp/SFmr7P0ssEN5JUsm78K8= atomicgo.dev/keyboard v0.2.9/go.mod h1:BC4w9g00XkxH/f1HXhW2sXmJFOCWbKn9xrOunSFtExQ= atomicgo.dev/schedule v0.1.0 h1:nTthAbhZS5YZmgYbb2+DH8uQIZcTlIrd4eYr3UQxEjs= atomicgo.dev/schedule v0.1.0/go.mod h1:xeUa3oAkiuHYh8bKiQBRojqAMq3PXXbJujjb0hw8pEU= -github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= -github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/MarvinJWendt/testza v0.1.0/go.mod h1:7AxNvlfeHP7Z/hDQ5JtE3OKYT3XFUeLCDE2DQninSqs= github.com/MarvinJWendt/testza v0.2.1/go.mod h1:God7bhG8n6uQxwdScay+gjm9/LnO4D3kkcZX4hv9Rp8= github.com/MarvinJWendt/testza v0.2.8/go.mod h1:nwIcjmr0Zz+Rcwfh3/4UhBp7ePKVhuBExvZqnKYWlII= @@ -17,6 +17,8 @@ github.com/MarvinJWendt/testza v0.3.0/go.mod h1:eFcL4I0idjtIx8P9C6KkAuLgATNKpX4/ github.com/MarvinJWendt/testza v0.4.2/go.mod h1:mSdhXiKH8sg/gQehJ63bINcCKp7RtYewEjXsvsVUPbE= github.com/MarvinJWendt/testza v0.5.2 h1:53KDo64C1z/h/d/stCYCPY69bt/OSwjq5KpFNwi+zB4= github.com/MarvinJWendt/testza v0.5.2/go.mod h1:xu53QFE5sCdjtMCKk8YMQ2MnymimEctc4n3EjyIYvEY= +github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= +github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= @@ -38,8 +40,8 @@ github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bF github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= -github.com/formancehq/go-libs/v2 v2.2.3 h1:7irBJ4NfSkJdVKxXPktqVAoQa7hJcejmrXgjdgh27Zk= -github.com/formancehq/go-libs/v2 v2.2.3/go.mod h1:JvBjEDWNf7izCy2dq/eI3aMc9d28gChBe1rjw5yYlAs= +github.com/formancehq/go-libs/v4 v4.1.0 h1:DZZYTrAG31wGBKa2VpU1/Ou2fQa1F6AZKsfdMR/166Q= +github.com/formancehq/go-libs/v4 v4.1.0/go.mod h1:iVE2pTLa4KNhqXkCpBAGzpGO8TdHTEjdJMAiCkkeb0A= github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= @@ -106,8 +108,8 @@ github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUt github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= -github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= +github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -118,10 +120,10 @@ github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/ github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus= -github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8= -github.com/onsi/gomega v1.38.0 h1:c/WX+w8SLAinvuKKQFh77WEucCnPk4j2OTUr7lt7BeY= -github.com/onsi/gomega v1.38.0/go.mod h1:OcXcwId0b9QsE7Y49u+BTrL4IdKOBOKnD6VQNTJEB6o= +github.com/onsi/ginkgo/v2 v2.27.4 h1:fcEcQW/A++6aZAZQNUmNjvA9PSOzefMJBerHJ4t8v8Y= +github.com/onsi/ginkgo/v2 v2.27.4/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo= +github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A= +github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -176,8 +178,6 @@ github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJu 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.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -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/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -198,8 +198,8 @@ 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.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= -golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= +golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= +golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -207,8 +207,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -216,8 +216,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -232,22 +232,22 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= +golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= +golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -256,8 +256,8 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= -golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= 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/tools/kubectl-stacks/list.go b/tools/kubectl-stacks/list.go index a6b70150..fa6ba72b 100644 --- a/tools/kubectl-stacks/list.go +++ b/tools/kubectl-stacks/list.go @@ -9,7 +9,7 @@ import ( "github.com/spf13/cobra" "k8s.io/cli-runtime/pkg/genericclioptions" - "github.com/formancehq/go-libs/v2/collectionutils" + "github.com/formancehq/go-libs/v4/collectionutils" "github.com/formancehq/operator/v3/api/formance.com/v1beta1" ) diff --git a/tools/utils/cmd/database-create.go b/tools/utils/cmd/database-create.go index 931bcb3d..d8cc963b 100644 --- a/tools/utils/cmd/database-create.go +++ b/tools/utils/cmd/database-create.go @@ -4,8 +4,8 @@ import ( "github.com/pkg/errors" "github.com/spf13/cobra" - "github.com/formancehq/go-libs/v2/bun/bunconnect" - "github.com/formancehq/go-libs/v2/bun/bunmigrate" + "github.com/formancehq/go-libs/v4/bun/bunconnect" + "github.com/formancehq/go-libs/v4/bun/bunmigrate" ) func NewDatabaseCreateCommand() *cobra.Command { diff --git a/tools/utils/cmd/database-drop.go b/tools/utils/cmd/database-drop.go index 6b76c50e..8cb6813f 100644 --- a/tools/utils/cmd/database-drop.go +++ b/tools/utils/cmd/database-drop.go @@ -4,8 +4,8 @@ import ( "github.com/pkg/errors" "github.com/spf13/cobra" - "github.com/formancehq/go-libs/v2/bun/bunconnect" - "github.com/formancehq/go-libs/v2/bun/bunmigrate" + "github.com/formancehq/go-libs/v4/bun/bunconnect" + "github.com/formancehq/go-libs/v4/bun/bunmigrate" ) func NewDatabaseDropCommand() *cobra.Command { diff --git a/tools/utils/cmd/database.go b/tools/utils/cmd/database.go index 42f903fc..be9d4f57 100644 --- a/tools/utils/cmd/database.go +++ b/tools/utils/cmd/database.go @@ -3,7 +3,7 @@ package cmd import ( "github.com/spf13/cobra" - "github.com/formancehq/go-libs/v2/bun/bunconnect" + "github.com/formancehq/go-libs/v4/bun/bunconnect" ) func NewDatabaseCommand() *cobra.Command { diff --git a/tools/utils/cmd/root.go b/tools/utils/cmd/root.go index 97148f21..3d402d76 100644 --- a/tools/utils/cmd/root.go +++ b/tools/utils/cmd/root.go @@ -5,8 +5,8 @@ import ( "github.com/spf13/cobra" - "github.com/formancehq/go-libs/v2/logging" - "github.com/formancehq/go-libs/v2/service" + "github.com/formancehq/go-libs/v4/logging" + "github.com/formancehq/go-libs/v4/service" ) var ( diff --git a/tools/utils/go.mod b/tools/utils/go.mod index c67a0afe..a57c00b3 100644 --- a/tools/utils/go.mod +++ b/tools/utils/go.mod @@ -5,7 +5,7 @@ go 1.25.0 toolchain go1.25.5 require ( - github.com/formancehq/go-libs/v2 v2.2.3 + github.com/formancehq/go-libs/v4 v4.1.0 github.com/pkg/errors v0.9.1 github.com/spf13/cobra v1.9.1 ) @@ -78,6 +78,7 @@ require ( go.opentelemetry.io/proto/otlp v1.9.0 // indirect go.uber.org/dig v1.19.0 // indirect go.uber.org/fx v1.24.0 // indirect + go.uber.org/mock v0.5.2 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect golang.org/x/net v0.51.0 // indirect diff --git a/tools/utils/go.sum b/tools/utils/go.sum index 6d96ac24..4d4d9eb3 100644 --- a/tools/utils/go.sum +++ b/tools/utils/go.sum @@ -1,9 +1,11 @@ -dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= -dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= +dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= filippo.io/edwards25519 v1.2.0 h1:crnVqOiS4jqYleHd9vaKZ+HKtHfllngJIiOpNpoJsjo= filippo.io/edwards25519 v1.2.0/go.mod h1:xzAOLCNug/yB62zG1bQ8uziwrIqIuxhctzJT18Q77mc= -github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= -github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= +github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= @@ -46,19 +48,23 @@ github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1x github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/containerd/continuity v0.4.3 h1:6HVkalIp+2u1ZLH1J/pYX2oBVXlJZvh1X1A7bEZ9Su8= -github.com/containerd/continuity v0.4.3/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= +github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4= +github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE= +github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= +github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= +github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= +github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= 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= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/docker/cli v27.3.1+incompatible h1:qEGdFBF3Xu6SCvCYhc7CzaQTlBmqDuzxPDpigSyeKQQ= -github.com/docker/cli v27.3.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/docker v27.5.1+incompatible h1:4PYU5dnBYqRQi0294d1FBECqT9ECWeQAIfE8q4YnPY8= -github.com/docker/docker v27.5.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= -github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/docker/cli v29.2.0+incompatible h1:9oBd9+YM7rxjZLfyMGxjraKBKE4/nVyvVfN4qNl9XRM= +github.com/docker/cli v29.2.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +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-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= @@ -66,8 +72,8 @@ github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/formancehq/go-libs/v2 v2.2.3 h1:7irBJ4NfSkJdVKxXPktqVAoQa7hJcejmrXgjdgh27Zk= -github.com/formancehq/go-libs/v2 v2.2.3/go.mod h1:JvBjEDWNf7izCy2dq/eI3aMc9d28gChBe1rjw5yYlAs= +github.com/formancehq/go-libs/v4 v4.1.0 h1:DZZYTrAG31wGBKa2VpU1/Ou2fQa1F6AZKsfdMR/166Q= +github.com/formancehq/go-libs/v4 v4.1.0/go.mod h1:iVE2pTLa4KNhqXkCpBAGzpGO8TdHTEjdJMAiCkkeb0A= github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug= github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -79,16 +85,14 @@ github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1 github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= -github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= -github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= -github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= +github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= 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/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= -github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8= +github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -122,20 +126,26 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= -github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= -github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/moby/moby/api v1.54.0 h1:7kbUgyiKcoBhm0UrWbdrMs7RX8dnwzURKVbZGy2GnL0= +github.com/moby/moby/api v1.54.0/go.mod h1:8mb+ReTlisw4pS6BRzCMts5M49W5M7bKt1cJy/YbAqc= +github.com/moby/moby/client v0.3.0 h1:UUGL5okry+Aomj3WhGt9Aigl3ZOxZGqR7XPo+RLPlKs= +github.com/moby/moby/client v0.3.0/go.mod h1:HJgFbJRvogDQjbM8fqc1MCEm4mIAGMLjXbgwoZp6jCQ= +github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs= +github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= +github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= +github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/onsi/ginkgo/v2 v2.22.1 h1:QW7tbJAUDyVDVOM5dFa7qaybo+CRfR7bemlQUN6Z8aM= -github.com/onsi/ginkgo/v2 v2.22.1/go.mod h1:S6aTpoRsSq2cZOd+pssHAlKW/Q/jZt6cPrPlnj4a1xM= +github.com/onsi/ginkgo/v2 v2.27.4 h1:fcEcQW/A++6aZAZQNUmNjvA9PSOzefMJBerHJ4t8v8Y= +github.com/onsi/ginkgo/v2 v2.27.4/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= -github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= -github.com/opencontainers/runc v1.1.14 h1:rgSuzbmgz5DUJjeSnw337TxDbRuqjs6iqQck/2weR6w= -github.com/opencontainers/runc v1.1.14/go.mod h1:E4C2z+7BxR7GHXp0hAY53mek+x49X1LjPNeMTfRGvOA= -github.com/ory/dockertest/v3 v3.11.0 h1:OiHcxKAvSDUwsEVh2BjxQQc/5EHz9n0va9awCtNGuyA= -github.com/ory/dockertest/v3 v3.11.0/go.mod h1:VIPxS1gwT9NpPOrfD3rACs8Y9Z7yhzO4SB194iUDnUI= +github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= +github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= +github.com/opencontainers/runc v1.2.8 h1:RnEICeDReapbZ5lZEgHvj7E9Q3Eex9toYmaGBsbvU5Q= +github.com/opencontainers/runc v1.2.8/go.mod h1:cC0YkmZcuvr+rtBZ6T7NBoVbMGNAdLa/21vIElJDOzI= +github.com/ory/dockertest/v3 v3.12.0 h1:3oV9d0sDzlSQfHtIaB5k6ghUCVMVLpAY8hwrqoCyRCw= +github.com/ory/dockertest/v3 v3.12.0/go.mod h1:aKNDTva3cp8dwOWwb9cWuX84aH5akkxXRvO7KCwWVjE= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -219,10 +229,16 @@ go.uber.org/fx v1.24.0 h1:wE8mruvpg2kiiL1Vqd0CC+tr0/24XIB10Iwp2lLWzkg= go.uber.org/fx v1.24.0/go.mod h1:AmDeGyS+ZARGKM4tlH4FY2Jr63VjbEDJHtqXTGP5hbo= 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.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko= +go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= 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.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= +golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo= golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= @@ -250,8 +266,6 @@ google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhH google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/tools/utils/main.go b/tools/utils/main.go index 02979bb7..1f7f856c 100644 --- a/tools/utils/main.go +++ b/tools/utils/main.go @@ -4,7 +4,7 @@ import ( "fmt" "os" - "github.com/formancehq/go-libs/v2/service" + "github.com/formancehq/go-libs/v4/service" "github.com/formancehq/operator/tools/utils/v3/cmd" ) From bbebbabf06a4b82c86aefe111d01477efc40cb70 Mon Sep 17 00:00:00 2001 From: Maxence Maireaux Date: Thu, 12 Mar 2026 12:07:21 +0100 Subject: [PATCH 2/6] feat(licence): add offline licence validation in operator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add centralized licence JWT validation directly in the operator using the embedded Formance RSA public key (same as go-libs/v4). This enables offline licence validation without any outbound network call. Behaviour by licence state: - Absent: operator deploys only non-EE modules (unchanged) - Valid: operator deploys all modules including EE (unchanged) - Expired/Invalid: operator continues reconciling non-EE modules, EE module reconciliation is skipped without deleting anything, a LicenceValid=False condition is set on the Stack and EE CRDs Key changes: - New LicenceValidator with embedded RSA public key (internal/core/licence.go) - EE gating in ForModule() — single enforcement point (controllers.go) - LicenceValid condition on Stack CRDs (stacks/init.go) - payments-ee image only used when licence is actually valid - Licence env vars only injected when licence is valid - Operator remains healthy regardless of licence state - 14 new unit tests covering JWT validation and condition behaviour --- cmd/main.go | 40 +++++++ go.mod | 1 + go.sum | 2 + internal/core/controllers.go | 19 +++ internal/core/licence.go | 116 ++++++++++++++++++ internal/core/licence_test.go | 129 ++++++++++++++++++++ internal/core/platform.go | 4 + internal/resources/licence/licence.go | 2 +- internal/resources/payments/init.go | 2 +- internal/resources/stacks/init.go | 28 +++++ internal/resources/stacks/licence_test.go | 136 ++++++++++++++++++++++ 11 files changed, 477 insertions(+), 2 deletions(-) create mode 100644 internal/core/licence.go create mode 100644 internal/core/licence_test.go create mode 100644 internal/resources/stacks/licence_test.go diff --git a/cmd/main.go b/cmd/main.go index ce980147..03b3024c 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -17,14 +17,17 @@ limitations under the License. package main import ( + "context" "crypto/tls" "flag" "fmt" "net/http" "os" + corev1 "k8s.io/api/core/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" utilruntime "k8s.io/apimachinery/pkg/util/runtime" clientgoscheme "k8s.io/client-go/kubernetes/scheme" _ "k8s.io/client-go/plugin/pkg/client/auth" @@ -45,6 +48,38 @@ var ( setupLog = ctrl.Log.WithName("setup") ) +func validateLicenceFromSecret(reader client.Reader, secretName string) (core.LicenceState, string) { + secret := &corev1.Secret{} + if err := reader.Get(context.Background(), types.NamespacedName{ + Name: secretName, + Namespace: "default", + }, secret); err != nil { + // Try all namespaces by looking for the secret with the formance label + secretList := &corev1.SecretList{} + if listErr := reader.List(context.Background(), secretList); listErr != nil { + return core.LicenceStateInvalid, fmt.Sprintf("failed to list secrets: %s", listErr) + } + found := false + for _, s := range secretList.Items { + if s.Name == secretName { + secret = &s + found = true + break + } + } + if !found { + return core.LicenceStateInvalid, fmt.Sprintf("licence secret %q not found", secretName) + } + } + + token, ok := secret.Data["token"] + if !ok { + return core.LicenceStateInvalid, "licence secret missing 'token' key" + } + + return core.ValidateLicenceToken(string(token)) +} + func init() { utilruntime.Must(clientgoscheme.AddToScheme(scheme)) utilruntime.Must(formancev1beta1.AddToScheme(scheme)) @@ -122,8 +157,13 @@ func main() { if licenceSecret != "" { setupLog.Info("licence management enabled", "secret", licenceSecret) + licenceState, licenceMessage := validateLicenceFromSecret(mgr.GetAPIReader(), licenceSecret) + platform.LicenceState = licenceState + platform.LicenceMessage = licenceMessage + setupLog.Info("licence validation result", "state", licenceState.String(), "message", licenceMessage) } else { setupLog.Info("licence management disabled") + platform.LicenceState = core.LicenceStateAbsent } if err := core.Setup(mgr, platform); err != nil { diff --git a/go.mod b/go.mod index 6a3722d4..7ccbe491 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ toolchain go1.25.5 require ( github.com/formancehq/go-libs/v4 v4.1.0 github.com/go-logr/logr v1.4.3 + github.com/golang-jwt/jwt/v5 v5.3.1 github.com/google/go-cmp v0.7.0 github.com/google/uuid v1.6.0 github.com/iancoleman/strcase v0.3.0 diff --git a/go.sum b/go.sum index 8de0948e..0af74231 100644 --- a/go.sum +++ b/go.sum @@ -42,6 +42,8 @@ github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= 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/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= +github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= diff --git a/internal/core/controllers.go b/internal/core/controllers.go index 40c263b4..ec379d73 100644 --- a/internal/core/controllers.go +++ b/internal/core/controllers.go @@ -133,6 +133,25 @@ func ForModule[T v1beta1.Module](underlyingController ModuleController[T]) Stack if err := removeAllModulesOwnedObjects(ctx, t, reconcilerOptions.Owns); err != nil { return err } + } else if t.IsEE() && ctx.GetPlatform().LicenceSecret != "" && ctx.GetPlatform().LicenceState != LicenceStateValid { + // EE module with an invalid/expired licence: skip reconciliation but don't delete anything. + // Non-EE modules and delete/finalizer flows are unaffected. + platform := ctx.GetPlatform() + reason := platform.LicenceState.String() + message := "Licence is " + reason + if platform.LicenceMessage != "" { + message = platform.LicenceMessage + } + t.GetConditions().AppendOrReplace(v1beta1.Condition{ + Type: "LicenceValid", + Status: metav1.ConditionFalse, + ObservedGeneration: t.GetGeneration(), + LastTransitionTime: metav1.Now(), + Message: message, + Reason: reason, + }, v1beta1.ConditionTypeMatch("LicenceValid")) + log.FromContext(ctx).Info("EE module reconciliation skipped: licence not valid", + "module", t.GetName(), "licenceState", reason) } else { err = underlyingController(ctx, stack, reconcilerOptions, t, moduleVersion) if err != nil { diff --git a/internal/core/licence.go b/internal/core/licence.go new file mode 100644 index 00000000..dfee5456 --- /dev/null +++ b/internal/core/licence.go @@ -0,0 +1,116 @@ +package core + +import ( + "crypto/rsa" + "crypto/x509" + "encoding/pem" + "errors" + "fmt" + + "github.com/golang-jwt/jwt/v5" +) + +// LicenceState represents the current state of the licence in the operator. +type LicenceState int + +const ( + LicenceStateAbsent LicenceState = iota // No licence configured + LicenceStateValid // JWT present and valid + LicenceStateExpired // JWT present but expired + LicenceStateInvalid // JWT present but malformed/bad signature +) + +func (s LicenceState) String() string { + switch s { + case LicenceStateAbsent: + return "Absent" + case LicenceStateValid: + return "Valid" + case LicenceStateExpired: + return "Expired" + case LicenceStateInvalid: + return "Invalid" + default: + return "Unknown" + } +} + +// formancePublicKey is the PEM-encoded RSA public key used to verify licence JWTs (RS256). +// This is the same key embedded in go-libs/v4/licence/public_key.go. +// It can be overridden at build time via ldflags: +// +// go build -ldflags "-X github.com/formancehq/operator/v3/internal/core.formancePublicKey=$(cat key.pem)" +// +//nolint:lll +var formancePublicKey = `-----BEGIN PUBLIC KEY----- +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA46LVe+BCO/go0MoKM4r7 +exTGeFSz10ra/hpFK0XJGVm6W42GTjFzNlNTCKQZBkF63STYK+o+FEFmSgMVxTjf +qA4GZGxYddukT4pNR+WaRLQSPxPkMsGrzoORtq8n2v4Y+m5jvYDXhLLmYsDNxVuv +SrAOtgJ0Ac8jJWXEu8Eqs0ferl9ftLRqrN+RfpXATT4fAgHBxVl5u1mFsQX6lo1B +N5m099Ni50Cmlauun883bS8xzLt/XLlk6vBaJKhfyDbkjcA4qN+33f5mih4v6EBP +txyeCg9yhHOfga61owAI+FOGEVW1OMTQ3PP/d2buiw9YrRAtBEXsJdhovc84jwmJ +sjA829+2nFR1Bq3jQ8nG4iTnF9yIwJr+l9reoV8Butskwld9mhry+dIimGpVUmy3 +psYmj910D1eH+tyuCGN7YAjD5+bXVUBPGfD1kJExtzjjyYruXD6trt7nchWrJIOu +D1I0OT3j+PWASm0c/AdN8BcV96HZhJBbCDK5GaQ9HSw+GVEpaqP9TY4uEz2werNq +cvjYlBS4FocA0ClsaDs9llIZVrI7kPYIeoO2KNWn7kp1q+awrNt677MLFmj7eqZ/ +jl/Sx2brq8e91kTG57Z2qRTkSGkCK20NFOI8E+m9bhhVRFw4RhY6g3lH1B5hd+dd +6TCk5eN7hTkosG21POe9goUCAwEAAQ== +-----END PUBLIC KEY-----` + +func parseFormancePublicKey() (*rsa.PublicKey, error) { + block, _ := pem.Decode([]byte(formancePublicKey)) + if block == nil { + return nil, fmt.Errorf("failed to decode embedded Formance public key") + } + + pub, err := x509.ParsePKIXPublicKey(block.Bytes) + if err != nil { + return nil, fmt.Errorf("failed to parse embedded Formance public key: %w", err) + } + + rsaPub, ok := pub.(*rsa.PublicKey) + if !ok { + return nil, fmt.Errorf("embedded Formance public key is not RSA") + } + + return rsaPub, nil +} + +// ValidateLicenceToken validates a licence JWT token and returns the licence state and a human-readable message. +// The validation uses the same logic as go-libs/v4/licence/jwt.go: +// RS256 signature with embedded Formance public key, expiration required. +func ValidateLicenceToken(token string) (LicenceState, string) { + if token == "" { + return LicenceStateAbsent, "" + } + + rsaPub, err := parseFormancePublicKey() + if err != nil { + return LicenceStateInvalid, fmt.Sprintf("public key error: %s", err) + } + + parser := jwt.NewParser( + jwt.WithValidMethods([]string{jwt.SigningMethodRS256.Alg()}), + jwt.WithExpirationRequired(), + ) + + parsed, err := parser.Parse(token, func(token *jwt.Token) (interface{}, error) { + return rsaPub, nil + }) + if err != nil { + if isTokenExpired(err) { + return LicenceStateExpired, "licence token is expired" + } + return LicenceStateInvalid, fmt.Sprintf("licence token validation failed: %s", err) + } + + if !parsed.Valid { + return LicenceStateInvalid, "licence token is not valid" + } + + return LicenceStateValid, "" +} + +func isTokenExpired(err error) bool { + return errors.Is(err, jwt.ErrTokenExpired) +} diff --git a/internal/core/licence_test.go b/internal/core/licence_test.go new file mode 100644 index 00000000..cc2bfc7d --- /dev/null +++ b/internal/core/licence_test.go @@ -0,0 +1,129 @@ +package core + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "encoding/pem" + "testing" + "time" + + "github.com/golang-jwt/jwt/v5" + "github.com/stretchr/testify/require" +) + +func generateTestRSAKeyPair(t *testing.T) (*rsa.PrivateKey, string) { + t.Helper() + privateKey, err := rsa.GenerateKey(rand.Reader, 2048) + require.NoError(t, err) + + pubBytes, err := x509.MarshalPKIXPublicKey(&privateKey.PublicKey) + require.NoError(t, err) + + pubPEM := pem.EncodeToMemory(&pem.Block{ + Type: "PUBLIC KEY", + Bytes: pubBytes, + }) + + return privateKey, string(pubPEM) +} + +func setTestKey(t *testing.T, key string) { + t.Helper() + original := formancePublicKey + formancePublicKey = key + t.Cleanup(func() { formancePublicKey = original }) +} + +func createToken(t *testing.T, claims jwt.MapClaims, key *rsa.PrivateKey) string { + t.Helper() + token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims) + s, err := token.SignedString(key) + require.NoError(t, err) + return s +} + +func TestValidateLicenceToken_EmptyToken(t *testing.T) { + state, msg := ValidateLicenceToken("") + require.Equal(t, LicenceStateAbsent, state) + require.Empty(t, msg) +} + +func TestValidateLicenceToken_ValidToken(t *testing.T) { + privateKey, pubPEM := generateTestRSAKeyPair(t) + setTestKey(t, pubPEM) + + token := createToken(t, jwt.MapClaims{ + "exp": time.Now().Add(time.Hour).Unix(), + }, privateKey) + + state, msg := ValidateLicenceToken(token) + require.Equal(t, LicenceStateValid, state) + require.Empty(t, msg) +} + +func TestValidateLicenceToken_ExpiredToken(t *testing.T) { + privateKey, pubPEM := generateTestRSAKeyPair(t) + setTestKey(t, pubPEM) + + token := createToken(t, jwt.MapClaims{ + "exp": time.Now().Add(-time.Hour).Unix(), + }, privateKey) + + state, msg := ValidateLicenceToken(token) + require.Equal(t, LicenceStateExpired, state) + require.Contains(t, msg, "expired") +} + +func TestValidateLicenceToken_MalformedToken(t *testing.T) { + state, msg := ValidateLicenceToken("not-a-jwt") + require.Equal(t, LicenceStateInvalid, state) + require.Contains(t, msg, "validation failed") +} + +func TestValidateLicenceToken_WrongSigningKey(t *testing.T) { + _, pubPEM := generateTestRSAKeyPair(t) + setTestKey(t, pubPEM) + + otherKey, _ := generateTestRSAKeyPair(t) + token := createToken(t, jwt.MapClaims{ + "exp": time.Now().Add(time.Hour).Unix(), + }, otherKey) + + state, msg := ValidateLicenceToken(token) + require.Equal(t, LicenceStateInvalid, state) + require.Contains(t, msg, "validation failed") +} + +func TestValidateLicenceToken_NoExpiration(t *testing.T) { + privateKey, pubPEM := generateTestRSAKeyPair(t) + setTestKey(t, pubPEM) + + token := createToken(t, jwt.MapClaims{}, privateKey) + + state, msg := ValidateLicenceToken(token) + require.Equal(t, LicenceStateInvalid, state) + require.Contains(t, msg, "validation failed") +} + +func TestValidateLicenceToken_ProductionKeyParses(t *testing.T) { + // Verify the embedded production key can be parsed without error. + // Token is signed with a random key, so validation must fail with + // a signature error, not a key parsing error. + otherKey, _ := generateTestRSAKeyPair(t) + token := createToken(t, jwt.MapClaims{ + "exp": time.Now().Add(time.Hour).Unix(), + }, otherKey) + + state, msg := ValidateLicenceToken(token) + require.Equal(t, LicenceStateInvalid, state) + require.Contains(t, msg, "validation failed") + require.NotContains(t, msg, "public key") +} + +func TestLicenceState_String(t *testing.T) { + require.Equal(t, "Absent", LicenceStateAbsent.String()) + require.Equal(t, "Valid", LicenceStateValid.String()) + require.Equal(t, "Expired", LicenceStateExpired.String()) + require.Equal(t, "Invalid", LicenceStateInvalid.String()) +} diff --git a/internal/core/platform.go b/internal/core/platform.go index f11c498b..12b3e2c5 100644 --- a/internal/core/platform.go +++ b/internal/core/platform.go @@ -10,4 +10,8 @@ type Platform struct { LicenceSecret string // The operator utils image version UtilsVersion string + // Licence validation state (computed from the licence secret JWT) + LicenceState LicenceState + // Human-readable message about the licence state + LicenceMessage string } diff --git a/internal/resources/licence/licence.go b/internal/resources/licence/licence.go index 7df0afed..911e2a74 100644 --- a/internal/resources/licence/licence.go +++ b/internal/resources/licence/licence.go @@ -15,7 +15,7 @@ func GetLicenceEnvVars(ctx core.Context, ownerName string, owner v1beta1.Depende var resourceReference *v1beta1.ResourceReference var err error - if platform.LicenceSecret != "" { + if platform.LicenceState == core.LicenceStateValid { resourceReference, err = resourcereferences.Create(ctx, owner, ownerName+"-licence", platform.LicenceSecret, &v1.Secret{}) if err != nil { return nil, nil, err diff --git a/internal/resources/payments/init.go b/internal/resources/payments/init.go index 557c1e7f..a357a67d 100644 --- a/internal/resources/payments/init.go +++ b/internal/resources/payments/init.go @@ -51,7 +51,7 @@ func Reconcile(ctx Context, stack *v1beta1.Stack, p *v1beta1.Payments, version s } imageName := "payments" - if ctx.GetPlatform().LicenceSecret != "" && + if ctx.GetPlatform().LicenceState == LicenceStateValid && (!semver.IsValid(version) || semver.Compare(version, "v3.2.0-beta.0") >= 0) { imageName = "payments-ee" } diff --git a/internal/resources/stacks/init.go b/internal/resources/stacks/init.go index 507c6eb1..eec451b8 100644 --- a/internal/resources/stacks/init.go +++ b/internal/resources/stacks/init.go @@ -186,6 +186,32 @@ func namespaceAnnotations(ctx Context, stack string) func(ns *corev1.Namespace) } } +func setLicenceCondition(ctx Context, stack *v1beta1.Stack) { + platform := ctx.GetPlatform() + if platform.LicenceSecret == "" { + stack.GetConditions().Delete(v1beta1.ConditionTypeMatch("LicenceValid")) + return + } + + condition := v1beta1.NewCondition("LicenceValid", stack.Generation) + switch platform.LicenceState { + case LicenceStateValid: + condition.SetStatus(metav1.ConditionTrue).SetReason("Valid").SetMessage("Licence is valid") + case LicenceStateExpired: + condition.SetStatus(metav1.ConditionFalse).SetReason("Expired").SetMessage("Licence token is expired") + case LicenceStateInvalid: + msg := "Licence token is invalid" + if platform.LicenceMessage != "" { + msg = platform.LicenceMessage + } + condition.SetStatus(metav1.ConditionFalse).SetReason("Invalid").SetMessage(msg) + default: + condition.SetStatus(metav1.ConditionFalse).SetReason("Unknown").SetMessage("Licence state unknown") + } + + stack.GetConditions().AppendOrReplace(*condition, v1beta1.ConditionTypeMatch("LicenceValid")) +} + var errAlreadyExist = errors.New("namespace already exists") func namespaceCreatedByAgent(ctx Context, stack *v1beta1.Stack) func(ns *corev1.Namespace) error { @@ -220,6 +246,8 @@ func Reconcile(ctx Context, stack *v1beta1.Stack) error { return err } + setLicenceCondition(ctx, stack) + if err := setModulesCondition(ctx, stack); err != nil { return err } diff --git a/internal/resources/stacks/licence_test.go b/internal/resources/stacks/licence_test.go new file mode 100644 index 00000000..39aafb3c --- /dev/null +++ b/internal/resources/stacks/licence_test.go @@ -0,0 +1,136 @@ +package stacks + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/formancehq/operator/v3/api/formance.com/v1beta1" + "github.com/formancehq/operator/v3/internal/core" +) + +type mockContext struct { + context.Context + platform core.Platform +} + +func (m *mockContext) GetClient() client.Client { return nil } +func (m *mockContext) GetScheme() *runtime.Scheme { return nil } +func (m *mockContext) GetAPIReader() client.Reader { return nil } +func (m *mockContext) GetPlatform() core.Platform { return m.platform } + +func newMockContext(platform core.Platform) core.Context { + return &mockContext{ + Context: context.Background(), + platform: platform, + } +} + +func newStack(name string) *v1beta1.Stack { + return &v1beta1.Stack{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Generation: 1, + }, + } +} + +func TestSetLicenceCondition_NoLicence(t *testing.T) { + stack := newStack("test") + ctx := newMockContext(core.Platform{LicenceSecret: ""}) + setLicenceCondition(ctx, stack) + + cond := stack.Status.Conditions.Get("LicenceValid") + require.Nil(t, cond, "no condition should be set when licence is absent") +} + +func TestSetLicenceCondition_ValidLicence(t *testing.T) { + stack := newStack("test") + ctx := newMockContext(core.Platform{ + LicenceSecret: "my-secret", + LicenceState: core.LicenceStateValid, + }) + setLicenceCondition(ctx, stack) + + cond := stack.Status.Conditions.Get("LicenceValid") + require.NotNil(t, cond) + require.Equal(t, metav1.ConditionTrue, cond.Status) + require.Equal(t, "Valid", cond.Reason) +} + +func TestSetLicenceCondition_ExpiredLicence(t *testing.T) { + stack := newStack("test") + ctx := newMockContext(core.Platform{ + LicenceSecret: "my-secret", + LicenceState: core.LicenceStateExpired, + }) + setLicenceCondition(ctx, stack) + + cond := stack.Status.Conditions.Get("LicenceValid") + require.NotNil(t, cond) + require.Equal(t, metav1.ConditionFalse, cond.Status) + require.Equal(t, "Expired", cond.Reason) + require.Contains(t, cond.Message, "expired") +} + +func TestSetLicenceCondition_InvalidLicence(t *testing.T) { + stack := newStack("test") + ctx := newMockContext(core.Platform{ + LicenceSecret: "my-secret", + LicenceState: core.LicenceStateInvalid, + LicenceMessage: "bad signature", + }) + setLicenceCondition(ctx, stack) + + cond := stack.Status.Conditions.Get("LicenceValid") + require.NotNil(t, cond) + require.Equal(t, metav1.ConditionFalse, cond.Status) + require.Equal(t, "Invalid", cond.Reason) + require.Equal(t, "bad signature", cond.Message) +} + +func TestSetLicenceCondition_TransitionFromValidToExpired(t *testing.T) { + stack := newStack("test") + + // First: valid + ctx := newMockContext(core.Platform{ + LicenceSecret: "my-secret", + LicenceState: core.LicenceStateValid, + }) + setLicenceCondition(ctx, stack) + cond := stack.Status.Conditions.Get("LicenceValid") + require.NotNil(t, cond) + require.Equal(t, metav1.ConditionTrue, cond.Status) + + // Then: expired + ctx2 := newMockContext(core.Platform{ + LicenceSecret: "my-secret", + LicenceState: core.LicenceStateExpired, + }) + setLicenceCondition(ctx2, stack) + cond = stack.Status.Conditions.Get("LicenceValid") + require.NotNil(t, cond) + require.Equal(t, metav1.ConditionFalse, cond.Status) + require.Equal(t, "Expired", cond.Reason) +} + +func TestSetLicenceCondition_RemovedWhenSecretCleared(t *testing.T) { + stack := newStack("test") + + // First: set with valid licence + ctx := newMockContext(core.Platform{ + LicenceSecret: "my-secret", + LicenceState: core.LicenceStateValid, + }) + setLicenceCondition(ctx, stack) + require.NotNil(t, stack.Status.Conditions.Get("LicenceValid")) + + // Then: licence secret removed + ctx2 := newMockContext(core.Platform{LicenceSecret: ""}) + setLicenceCondition(ctx2, stack) + require.Nil(t, stack.Status.Conditions.Get("LicenceValid")) +} From f4f81768b0d5e9f1f6987069d4ee7ae369d00301 Mon Sep 17 00:00:00 2001 From: Maxence Maireaux Date: Thu, 12 Mar 2026 12:47:12 +0100 Subject: [PATCH 3/6] fix(licence): address CodeRabbit review feedback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Re-resolve licence state from Secret on each EE reconciliation, not just at startup — prevents stale state when token expires or Secret is updated while operator is running - Handle all licence state transitions in ForModule(): Valid → write LicenceValid=True (clears stale False condition) Absent → skip EE with LicenceValid=False/Absent Expired/Invalid → skip EE with LicenceValid=False - Remove dangerous cluster-wide Secret fallback scan; use explicit namespace via --licence-namespace flag (defaults to POD_NAMESPACE) - Treat empty token value as Invalid, not Absent - Remove env vars dump from utils startup logs (security) - Add SetFormancePublicKeyForTest for cross-package test overrides - Add tests: EmptyToken, SecretNotFound, real Secret-based conditions --- cmd/main.go | 58 +++----- internal/core/controllers.go | 73 +++++++--- internal/core/licence.go | 44 ++++++ internal/core/licence_test.go | 4 +- internal/core/platform.go | 2 + internal/resources/stacks/init.go | 10 +- internal/resources/stacks/licence_test.go | 159 ++++++++++++++++++---- tools/utils/cmd/root.go | 6 - 8 files changed, 260 insertions(+), 96 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index 03b3024c..dfe8044f 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -17,17 +17,14 @@ limitations under the License. package main import ( - "context" "crypto/tls" "flag" "fmt" "net/http" "os" - corev1 "k8s.io/api/core/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" utilruntime "k8s.io/apimachinery/pkg/util/runtime" clientgoscheme "k8s.io/client-go/kubernetes/scheme" _ "k8s.io/client-go/plugin/pkg/client/auth" @@ -48,38 +45,6 @@ var ( setupLog = ctrl.Log.WithName("setup") ) -func validateLicenceFromSecret(reader client.Reader, secretName string) (core.LicenceState, string) { - secret := &corev1.Secret{} - if err := reader.Get(context.Background(), types.NamespacedName{ - Name: secretName, - Namespace: "default", - }, secret); err != nil { - // Try all namespaces by looking for the secret with the formance label - secretList := &corev1.SecretList{} - if listErr := reader.List(context.Background(), secretList); listErr != nil { - return core.LicenceStateInvalid, fmt.Sprintf("failed to list secrets: %s", listErr) - } - found := false - for _, s := range secretList.Items { - if s.Name == secretName { - secret = &s - found = true - break - } - } - if !found { - return core.LicenceStateInvalid, fmt.Sprintf("licence secret %q not found", secretName) - } - } - - token, ok := secret.Data["token"] - if !ok { - return core.LicenceStateInvalid, "licence secret missing 'token' key" - } - - return core.ValidateLicenceToken(string(token)) -} - func init() { utilruntime.Must(clientgoscheme.AddToScheme(scheme)) utilruntime.Must(formancev1beta1.AddToScheme(scheme)) @@ -96,6 +61,7 @@ func main() { region string env string licenceSecret string + licenceNamespace string utilsVersion string ) flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.") @@ -106,6 +72,7 @@ func main() { flag.StringVar(®ion, "region", "eu-west-1", "The cloud region in use for the operator") flag.StringVar(&env, "env", "staging", "The current environment in use for the operator") flag.StringVar(&licenceSecret, "licence-secret", "", "The licence secret that contains the token and the issuer") + flag.StringVar(&licenceNamespace, "licence-namespace", "", "The namespace where the licence secret lives (defaults to operator namespace)") flag.StringVar(&utilsVersion, "utils-version", "latest", "The version of the operator utils image") opts := zap.Options{ Development: false, @@ -148,16 +115,25 @@ func main() { os.Exit(1) } + if licenceNamespace == "" { + licenceNamespace = os.Getenv("POD_NAMESPACE") + if licenceNamespace == "" { + licenceNamespace = "default" + } + } + platform := core.Platform{ - Region: region, - Environment: env, - LicenceSecret: licenceSecret, - UtilsVersion: utilsVersion, + Region: region, + Environment: env, + LicenceSecret: licenceSecret, + LicenceNamespace: licenceNamespace, + UtilsVersion: utilsVersion, } if licenceSecret != "" { - setupLog.Info("licence management enabled", "secret", licenceSecret) - licenceState, licenceMessage := validateLicenceFromSecret(mgr.GetAPIReader(), licenceSecret) + setupLog.Info("licence management enabled", "secret", licenceSecret, "namespace", licenceNamespace) + // Initial validation at startup (will be re-resolved on each EE reconciliation) + licenceState, licenceMessage := core.ResolveLicenceState(mgr.GetAPIReader(), licenceSecret, licenceNamespace) platform.LicenceState = licenceState platform.LicenceMessage = licenceMessage setupLog.Info("licence validation result", "state", licenceState.String(), "message", licenceMessage) diff --git a/internal/core/controllers.go b/internal/core/controllers.go index ec379d73..28787a8d 100644 --- a/internal/core/controllers.go +++ b/internal/core/controllers.go @@ -133,25 +133,64 @@ func ForModule[T v1beta1.Module](underlyingController ModuleController[T]) Stack if err := removeAllModulesOwnedObjects(ctx, t, reconcilerOptions.Owns); err != nil { return err } - } else if t.IsEE() && ctx.GetPlatform().LicenceSecret != "" && ctx.GetPlatform().LicenceState != LicenceStateValid { - // EE module with an invalid/expired licence: skip reconciliation but don't delete anything. - // Non-EE modules and delete/finalizer flows are unaffected. + } else if t.IsEE() { platform := ctx.GetPlatform() - reason := platform.LicenceState.String() - message := "Licence is " + reason - if platform.LicenceMessage != "" { - message = platform.LicenceMessage + licenceState := platform.LicenceState + licenceMessage := platform.LicenceMessage + + // Re-resolve licence state from Secret if a licence is configured, + // so we always have fresh state (not stale from startup). + if platform.LicenceSecret != "" { + licenceState, licenceMessage = ResolveLicenceState( + ctx.GetAPIReader(), platform.LicenceSecret, platform.LicenceNamespace) + } + + switch licenceState { + case LicenceStateValid: + // Licence valid: clear any previous LicenceValid=False condition and proceed + t.GetConditions().AppendOrReplace(v1beta1.Condition{ + Type: "LicenceValid", + Status: metav1.ConditionTrue, + ObservedGeneration: t.GetGeneration(), + LastTransitionTime: metav1.Now(), + Message: "Licence is valid", + Reason: "Valid", + }, v1beta1.ConditionTypeMatch("LicenceValid")) + + err = underlyingController(ctx, stack, reconcilerOptions, t, moduleVersion) + if err != nil { + return err + } + case LicenceStateAbsent: + // No licence configured: EE modules should not be reconciled + t.GetConditions().AppendOrReplace(v1beta1.Condition{ + Type: "LicenceValid", + Status: metav1.ConditionFalse, + ObservedGeneration: t.GetGeneration(), + LastTransitionTime: metav1.Now(), + Message: "No licence configured", + Reason: "Absent", + }, v1beta1.ConditionTypeMatch("LicenceValid")) + log.FromContext(ctx).Info("EE module reconciliation skipped: no licence configured", + "module", t.GetName()) + default: + // Expired or Invalid: skip EE reconciliation, set condition + reason := licenceState.String() + message := "Licence is " + reason + if licenceMessage != "" { + message = licenceMessage + } + t.GetConditions().AppendOrReplace(v1beta1.Condition{ + Type: "LicenceValid", + Status: metav1.ConditionFalse, + ObservedGeneration: t.GetGeneration(), + LastTransitionTime: metav1.Now(), + Message: message, + Reason: reason, + }, v1beta1.ConditionTypeMatch("LicenceValid")) + log.FromContext(ctx).Info("EE module reconciliation skipped: licence not valid", + "module", t.GetName(), "licenceState", reason) } - t.GetConditions().AppendOrReplace(v1beta1.Condition{ - Type: "LicenceValid", - Status: metav1.ConditionFalse, - ObservedGeneration: t.GetGeneration(), - LastTransitionTime: metav1.Now(), - Message: message, - Reason: reason, - }, v1beta1.ConditionTypeMatch("LicenceValid")) - log.FromContext(ctx).Info("EE module reconciliation skipped: licence not valid", - "module", t.GetName(), "licenceState", reason) } else { err = underlyingController(ctx, stack, reconcilerOptions, t, moduleVersion) if err != nil { diff --git a/internal/core/licence.go b/internal/core/licence.go index dfee5456..81947f86 100644 --- a/internal/core/licence.go +++ b/internal/core/licence.go @@ -1,6 +1,7 @@ package core import ( + "context" "crypto/rsa" "crypto/x509" "encoding/pem" @@ -8,6 +9,10 @@ import ( "fmt" "github.com/golang-jwt/jwt/v5" + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" ) // LicenceState represents the current state of the licence in the operator. @@ -111,6 +116,45 @@ func ValidateLicenceToken(token string) (LicenceState, string) { return LicenceStateValid, "" } +// SetFormancePublicKeyForTest overrides the embedded public key for testing and restores it on cleanup. +func SetFormancePublicKeyForTest(t interface { + Helper() + Cleanup(func()) +}, key string) { + t.Helper() + original := formancePublicKey + formancePublicKey = key + t.Cleanup(func() { formancePublicKey = original }) +} + func isTokenExpired(err error) bool { return errors.Is(err, jwt.ErrTokenExpired) } + +// ResolveLicenceState reads the licence Secret by name from the operator's namespace, +// extracts the JWT token, and validates it. This is called during each EE reconciliation +// to ensure the licence state is always fresh (not stale from startup). +func ResolveLicenceState(reader client.Reader, secretName string, operatorNamespace string) (LicenceState, string) { + if secretName == "" { + return LicenceStateAbsent, "" + } + + secret := &corev1.Secret{} + err := reader.Get(context.Background(), types.NamespacedName{ + Name: secretName, + Namespace: operatorNamespace, + }, secret) + if err != nil { + if apierrors.IsNotFound(err) { + return LicenceStateInvalid, fmt.Sprintf("licence secret %q not found in namespace %q", secretName, operatorNamespace) + } + return LicenceStateInvalid, fmt.Sprintf("failed to read licence secret %q: %s", secretName, err) + } + + token, ok := secret.Data["token"] + if !ok || len(token) == 0 { + return LicenceStateInvalid, "licence secret missing non-empty 'token' key" + } + + return ValidateLicenceToken(string(token)) +} diff --git a/internal/core/licence_test.go b/internal/core/licence_test.go index cc2bfc7d..cafb214a 100644 --- a/internal/core/licence_test.go +++ b/internal/core/licence_test.go @@ -30,9 +30,7 @@ func generateTestRSAKeyPair(t *testing.T) (*rsa.PrivateKey, string) { func setTestKey(t *testing.T, key string) { t.Helper() - original := formancePublicKey - formancePublicKey = key - t.Cleanup(func() { formancePublicKey = original }) + SetFormancePublicKeyForTest(t, key) } func createToken(t *testing.T, claims jwt.MapClaims, key *rsa.PrivateKey) string { diff --git a/internal/core/platform.go b/internal/core/platform.go index 12b3e2c5..31152589 100644 --- a/internal/core/platform.go +++ b/internal/core/platform.go @@ -10,6 +10,8 @@ type Platform struct { LicenceSecret string // The operator utils image version UtilsVersion string + // Namespace where the licence secret lives + LicenceNamespace string // Licence validation state (computed from the licence secret JWT) LicenceState LicenceState // Human-readable message about the licence state diff --git a/internal/resources/stacks/init.go b/internal/resources/stacks/init.go index eec451b8..15f58c87 100644 --- a/internal/resources/stacks/init.go +++ b/internal/resources/stacks/init.go @@ -193,16 +193,20 @@ func setLicenceCondition(ctx Context, stack *v1beta1.Stack) { return } + // Re-resolve from Secret for fresh state + licenceState, licenceMessage := ResolveLicenceState( + ctx.GetAPIReader(), platform.LicenceSecret, platform.LicenceNamespace) + condition := v1beta1.NewCondition("LicenceValid", stack.Generation) - switch platform.LicenceState { + switch licenceState { case LicenceStateValid: condition.SetStatus(metav1.ConditionTrue).SetReason("Valid").SetMessage("Licence is valid") case LicenceStateExpired: condition.SetStatus(metav1.ConditionFalse).SetReason("Expired").SetMessage("Licence token is expired") case LicenceStateInvalid: msg := "Licence token is invalid" - if platform.LicenceMessage != "" { - msg = platform.LicenceMessage + if licenceMessage != "" { + msg = licenceMessage } condition.SetStatus(metav1.ConditionFalse).SetReason("Invalid").SetMessage(msg) default: diff --git a/internal/resources/stacks/licence_test.go b/internal/resources/stacks/licence_test.go index 39aafb3c..63ae0ae3 100644 --- a/internal/resources/stacks/licence_test.go +++ b/internal/resources/stacks/licence_test.go @@ -2,12 +2,20 @@ package stacks import ( "context" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "encoding/pem" "testing" + "time" + "github.com/golang-jwt/jwt/v5" "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" "github.com/formancehq/operator/v3/api/formance.com/v1beta1" "github.com/formancehq/operator/v3/internal/core" @@ -15,21 +23,81 @@ import ( type mockContext struct { context.Context - platform core.Platform + platform core.Platform + apiReader client.Reader } func (m *mockContext) GetClient() client.Client { return nil } func (m *mockContext) GetScheme() *runtime.Scheme { return nil } -func (m *mockContext) GetAPIReader() client.Reader { return nil } +func (m *mockContext) GetAPIReader() client.Reader { return m.apiReader } func (m *mockContext) GetPlatform() core.Platform { return m.platform } -func newMockContext(platform core.Platform) core.Context { +func newMockContext(platform core.Platform, objects ...client.Object) core.Context { + scheme := runtime.NewScheme() + _ = corev1.AddToScheme(scheme) + builder := fake.NewClientBuilder().WithScheme(scheme) + if len(objects) > 0 { + builder = builder.WithObjects(objects...) + } return &mockContext{ - Context: context.Background(), - platform: platform, + Context: context.Background(), + platform: platform, + apiReader: builder.Build(), } } +func newLicenceSecret(name, namespace, token string) *corev1.Secret { + return &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Data: map[string][]byte{ + "token": []byte(token), + "issuer": []byte("https://license.formance.cloud/keys"), + }, + } +} + +func generateValidToken(t *testing.T) string { + t.Helper() + privateKey, err := rsa.GenerateKey(rand.Reader, 2048) + require.NoError(t, err) + + pubBytes, err := x509.MarshalPKIXPublicKey(&privateKey.PublicKey) + require.NoError(t, err) + pubPEM := pem.EncodeToMemory(&pem.Block{Type: "PUBLIC KEY", Bytes: pubBytes}) + + // Override the embedded key for testing + core.SetFormancePublicKeyForTest(t, string(pubPEM)) + + token := jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{ + "exp": time.Now().Add(time.Hour).Unix(), + }) + s, err := token.SignedString(privateKey) + require.NoError(t, err) + return s +} + +func generateExpiredToken(t *testing.T) string { + t.Helper() + privateKey, err := rsa.GenerateKey(rand.Reader, 2048) + require.NoError(t, err) + + pubBytes, err := x509.MarshalPKIXPublicKey(&privateKey.PublicKey) + require.NoError(t, err) + pubPEM := pem.EncodeToMemory(&pem.Block{Type: "PUBLIC KEY", Bytes: pubBytes}) + + core.SetFormancePublicKeyForTest(t, string(pubPEM)) + + token := jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{ + "exp": time.Now().Add(-time.Hour).Unix(), + }) + s, err := token.SignedString(privateKey) + require.NoError(t, err) + return s +} + func newStack(name string) *v1beta1.Stack { return &v1beta1.Stack{ ObjectMeta: metav1.ObjectMeta{ @@ -50,10 +118,12 @@ func TestSetLicenceCondition_NoLicence(t *testing.T) { func TestSetLicenceCondition_ValidLicence(t *testing.T) { stack := newStack("test") + token := generateValidToken(t) + secret := newLicenceSecret("my-secret", "operator", token) ctx := newMockContext(core.Platform{ - LicenceSecret: "my-secret", - LicenceState: core.LicenceStateValid, - }) + LicenceSecret: "my-secret", + LicenceNamespace: "operator", + }, secret) setLicenceCondition(ctx, stack) cond := stack.Status.Conditions.Get("LicenceValid") @@ -64,10 +134,12 @@ func TestSetLicenceCondition_ValidLicence(t *testing.T) { func TestSetLicenceCondition_ExpiredLicence(t *testing.T) { stack := newStack("test") + token := generateExpiredToken(t) + secret := newLicenceSecret("my-secret", "operator", token) ctx := newMockContext(core.Platform{ - LicenceSecret: "my-secret", - LicenceState: core.LicenceStateExpired, - }) + LicenceSecret: "my-secret", + LicenceNamespace: "operator", + }, secret) setLicenceCondition(ctx, stack) cond := stack.Status.Conditions.Get("LicenceValid") @@ -79,10 +151,40 @@ func TestSetLicenceCondition_ExpiredLicence(t *testing.T) { func TestSetLicenceCondition_InvalidLicence(t *testing.T) { stack := newStack("test") + secret := newLicenceSecret("my-secret", "operator", "not-a-jwt") + ctx := newMockContext(core.Platform{ + LicenceSecret: "my-secret", + LicenceNamespace: "operator", + }, secret) + setLicenceCondition(ctx, stack) + + cond := stack.Status.Conditions.Get("LicenceValid") + require.NotNil(t, cond) + require.Equal(t, metav1.ConditionFalse, cond.Status) + require.Equal(t, "Invalid", cond.Reason) +} + +func TestSetLicenceCondition_EmptyToken(t *testing.T) { + stack := newStack("test") + secret := newLicenceSecret("my-secret", "operator", "") + ctx := newMockContext(core.Platform{ + LicenceSecret: "my-secret", + LicenceNamespace: "operator", + }, secret) + setLicenceCondition(ctx, stack) + + cond := stack.Status.Conditions.Get("LicenceValid") + require.NotNil(t, cond) + require.Equal(t, metav1.ConditionFalse, cond.Status) + require.Equal(t, "Invalid", cond.Reason) +} + +func TestSetLicenceCondition_SecretNotFound(t *testing.T) { + stack := newStack("test") + // No secret created — should be Invalid ctx := newMockContext(core.Platform{ - LicenceSecret: "my-secret", - LicenceState: core.LicenceStateInvalid, - LicenceMessage: "bad signature", + LicenceSecret: "missing-secret", + LicenceNamespace: "operator", }) setLicenceCondition(ctx, stack) @@ -90,27 +192,30 @@ func TestSetLicenceCondition_InvalidLicence(t *testing.T) { require.NotNil(t, cond) require.Equal(t, metav1.ConditionFalse, cond.Status) require.Equal(t, "Invalid", cond.Reason) - require.Equal(t, "bad signature", cond.Message) } func TestSetLicenceCondition_TransitionFromValidToExpired(t *testing.T) { stack := newStack("test") // First: valid + validToken := generateValidToken(t) + secret := newLicenceSecret("my-secret", "operator", validToken) ctx := newMockContext(core.Platform{ - LicenceSecret: "my-secret", - LicenceState: core.LicenceStateValid, - }) + LicenceSecret: "my-secret", + LicenceNamespace: "operator", + }, secret) setLicenceCondition(ctx, stack) cond := stack.Status.Conditions.Get("LicenceValid") require.NotNil(t, cond) require.Equal(t, metav1.ConditionTrue, cond.Status) - // Then: expired + // Then: expired (new context with expired token) + expiredToken := generateExpiredToken(t) + secret2 := newLicenceSecret("my-secret", "operator", expiredToken) ctx2 := newMockContext(core.Platform{ - LicenceSecret: "my-secret", - LicenceState: core.LicenceStateExpired, - }) + LicenceSecret: "my-secret", + LicenceNamespace: "operator", + }, secret2) setLicenceCondition(ctx2, stack) cond = stack.Status.Conditions.Get("LicenceValid") require.NotNil(t, cond) @@ -122,14 +227,16 @@ func TestSetLicenceCondition_RemovedWhenSecretCleared(t *testing.T) { stack := newStack("test") // First: set with valid licence + validToken := generateValidToken(t) + secret := newLicenceSecret("my-secret", "operator", validToken) ctx := newMockContext(core.Platform{ - LicenceSecret: "my-secret", - LicenceState: core.LicenceStateValid, - }) + LicenceSecret: "my-secret", + LicenceNamespace: "operator", + }, secret) setLicenceCondition(ctx, stack) require.NotNil(t, stack.Status.Conditions.Get("LicenceValid")) - // Then: licence secret removed + // Then: licence secret removed from platform config ctx2 := newMockContext(core.Platform{LicenceSecret: ""}) setLicenceCondition(ctx2, stack) require.Nil(t, stack.Status.Conditions.Get("LicenceValid")) diff --git a/tools/utils/cmd/root.go b/tools/utils/cmd/root.go index 3d402d76..d322baae 100644 --- a/tools/utils/cmd/root.go +++ b/tools/utils/cmd/root.go @@ -1,8 +1,6 @@ package cmd import ( - "os" - "github.com/spf13/cobra" "github.com/formancehq/go-libs/v4/logging" @@ -22,10 +20,6 @@ var RootCmd = &cobra.Command{ PersistentPreRunE: func(cmd *cobra.Command, args []string) error { logger := logging.NewDefaultLogger(cmd.OutOrStdout(), service.IsDebug(cmd), false, false) logger.Infof("Starting application") - logger.Debugf("Environment variables:") - for _, v := range os.Environ() { - logger.Debugf(v) - } cmd.SetContext(logging.ContextWithLogger(cmd.Context(), logger)) return nil }, From 815d20c861106d2d08166d865d3f7ddb6166237e Mon Sep 17 00:00:00 2001 From: Maxence Maireaux Date: Thu, 19 Mar 2026 16:04:37 +0100 Subject: [PATCH 4/6] fix(tests): set LicenceState to Valid in test bootstrap The offline licence validation feature gates EE module reconciliation behind a valid licence. Integration tests were not configuring any licence state, causing all EE modules (Auth, Wallets, Orchestration) to be skipped and their deployments never created, resulting in timeouts. --- internal/tests/internal/bootstrap.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/internal/tests/internal/bootstrap.go b/internal/tests/internal/bootstrap.go index 47bae403..d0e57834 100644 --- a/internal/tests/internal/bootstrap.go +++ b/internal/tests/internal/bootstrap.go @@ -102,13 +102,15 @@ var _ = BeforeSuite(func() { }) Expect(err).ToNot(HaveOccurred()) coreMgr = core.NewDefaultManager(mgr, core.Platform{ - Region: "testing", - Environment: "testing", + Region: "testing", + Environment: "testing", + LicenceState: core.LicenceStateValid, }) Expect(core.Setup(mgr, core.Platform{ - Region: "us-west-1", - Environment: "staging", + Region: "us-west-1", + Environment: "staging", + LicenceState: core.LicenceStateValid, })).To(Succeed()) err = ctrl.NewControllerManagedBy(mgr). From 693a7d037bcc8e6aad11c5372ac267c10b73fc1d Mon Sep 17 00:00:00 2001 From: Maxence Maireaux Date: Thu, 19 Mar 2026 16:16:40 +0100 Subject: [PATCH 5/6] fix(tests): configure full test licence with Secret and JWT The previous fix only set LicenceState without a LicenceSecret, causing GetLicenceEnvVars to create ResourceReferences to an empty secret name. This broke EE module reconciliation and caused cascading failures in non-EE tests. Now the test bootstrap: - Generates a test RSA key pair and overrides the embedded public key - Signs a valid JWT token - Creates a licence Secret in the test cluster - Configures Platform with LicenceSecret, LicenceNamespace, and LicenceState so all licence checks pass properly --- internal/tests/internal/bootstrap.go | 77 ++++++++++++++++++++++++---- 1 file changed, 67 insertions(+), 10 deletions(-) diff --git a/internal/tests/internal/bootstrap.go b/internal/tests/internal/bootstrap.go index d0e57834..56ddb6fa 100644 --- a/internal/tests/internal/bootstrap.go +++ b/internal/tests/internal/bootstrap.go @@ -2,15 +2,22 @@ package internal import ( "context" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "encoding/pem" "os" "path/filepath" osRuntime "runtime" "time" + "github.com/golang-jwt/jwt/v5" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" appsv1 "k8s.io/api/apps/v1" batchv1 "k8s.io/api/batch/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes/scheme" @@ -31,6 +38,11 @@ import ( _ "github.com/formancehq/operator/v3/internal/resources" ) +const ( + testLicenceSecretName = "formance-licence" + testLicenceSecretNamespace = "default" +) + var ( ctx context.Context cancel func() @@ -51,6 +63,29 @@ func init() { } } +// generateTestLicence creates a test RSA key pair, overrides the embedded public key, +// and returns a signed JWT token valid for 24 hours. +func generateTestLicence() string { + privateKey, err := rsa.GenerateKey(rand.Reader, 2048) + Expect(err).ToNot(HaveOccurred()) + + pubBytes, err := x509.MarshalPKIXPublicKey(&privateKey.PublicKey) + Expect(err).ToNot(HaveOccurred()) + + pubPEM := pem.EncodeToMemory(&pem.Block{Type: "PUBLIC KEY", Bytes: pubBytes}) + + // Override the embedded Formance public key so the test JWT validates + core.SetFormancePublicKeyForTest(GinkgoT(), string(pubPEM)) + + token := jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{ + "exp": time.Now().Add(24 * time.Hour).Unix(), + }) + signed, err := token.SignedString(privateKey) + Expect(err).ToNot(HaveOccurred()) + + return signed +} + var _ = BeforeSuite(func() { logf.SetLogger(zap.New(zap.WriteTo(os.Stdout), zap.UseDevMode(true))) ctx, cancel = context.WithCancel(context.Background()) @@ -88,6 +123,36 @@ var _ = BeforeSuite(func() { Expect(err).NotTo(HaveOccurred()) Expect(k8sClient).NotTo(BeNil()) + // Generate a test licence JWT and create the Secret in the cluster + licenceToken := generateTestLicence() + + licenceSecret := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: testLicenceSecretNamespace, + }, + } + // default namespace should already exist, ignore error + _ = k8sClient.Create(context.Background(), licenceSecret) + + Expect(k8sClient.Create(context.Background(), &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: testLicenceSecretName, + Namespace: testLicenceSecretNamespace, + }, + Data: map[string][]byte{ + "token": []byte(licenceToken), + "issuer": []byte("https://license.formance.cloud/keys"), + }, + })).To(Succeed()) + + testPlatform := core.Platform{ + Region: "us-west-1", + Environment: "staging", + LicenceSecret: testLicenceSecretName, + LicenceNamespace: testLicenceSecretNamespace, + LicenceState: core.LicenceStateValid, + } + ctx, cancel = context.WithCancel(context.Background()) mgr, err := ctrl.NewManager(restConfig, ctrl.Options{ Scheme: GetScheme(), @@ -101,17 +166,9 @@ var _ = BeforeSuite(func() { }, }) Expect(err).ToNot(HaveOccurred()) - coreMgr = core.NewDefaultManager(mgr, core.Platform{ - Region: "testing", - Environment: "testing", - LicenceState: core.LicenceStateValid, - }) + coreMgr = core.NewDefaultManager(mgr, testPlatform) - Expect(core.Setup(mgr, core.Platform{ - Region: "us-west-1", - Environment: "staging", - LicenceState: core.LicenceStateValid, - })).To(Succeed()) + Expect(core.Setup(mgr, testPlatform)).To(Succeed()) err = ctrl.NewControllerManagedBy(mgr). For(&appsv1.Deployment{}). From dc68520fa61387b34b381b74317446d83f9e1052 Mon Sep 17 00:00:00 2001 From: Maxence Maireaux Date: Thu, 19 Mar 2026 16:21:51 +0100 Subject: [PATCH 6/6] fix(tests): add StackLabel to licence secret for ResourceReference lookup The ResourceReference controller finds secrets by filtering on the formance.com/stack label. Without this label, the licence secret was invisible to the resource reference reconciler, causing "item not found: formance-licence" errors that blocked module reconciliation. --- internal/tests/internal/bootstrap.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/tests/internal/bootstrap.go b/internal/tests/internal/bootstrap.go index 56ddb6fa..b4ec09cc 100644 --- a/internal/tests/internal/bootstrap.go +++ b/internal/tests/internal/bootstrap.go @@ -138,6 +138,9 @@ var _ = BeforeSuite(func() { ObjectMeta: metav1.ObjectMeta{ Name: testLicenceSecretName, Namespace: testLicenceSecretNamespace, + Labels: map[string]string{ + v1beta1.StackLabel: "any", + }, }, Data: map[string][]byte{ "token": []byte(licenceToken),