From 8ef41ff864d620011ced0b8b5f78d16bebbba091 Mon Sep 17 00:00:00 2001 From: "@x10an14-nav" Date: Wed, 28 Jan 2026 11:51:24 +0100 Subject: [PATCH 1/5] feature(aiven): allow users to access streams Like we do for topics Co-authored-by: @sindrerh2 Co-authored-by: @ybelmekk --- go.mod | 73 ++++---- go.sum | 174 ++++++++---------- internal/aiven/aiven_services/stream.go | 28 +++ internal/aiven/command/aiven.go | 1 + internal/aiven/command/create.go | 1 + internal/aiven/command/create_kafka.go | 1 - internal/aiven/command/create_stream.go | 53 ++++++ internal/aiven/command/flag/flag.go | 9 + internal/aiven/command/grant_access.go | 19 ++ internal/aiven/command/grant_access_stream.go | 60 ++++++ 10 files changed, 286 insertions(+), 133 deletions(-) create mode 100644 internal/aiven/aiven_services/stream.go create mode 100644 internal/aiven/command/create_stream.go create mode 100644 internal/aiven/command/grant_access.go create mode 100644 internal/aiven/command/grant_access_stream.go diff --git a/go.mod b/go.mod index e834ff8c..71d1935b 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( github.com/mitchellh/go-ps v1.0.0 github.com/nais/device v1.7.3 github.com/nais/krakend/pkg/migration v0.0.0-20251112211103-82b954ae962b - github.com/nais/liberator v0.0.0-20251105145237-b406841758d4 + github.com/nais/liberator v0.0.0-20260128091017-350fb9813ed9 github.com/nais/naistrix v0.17.0 github.com/pelletier/go-toml/v2 v2.2.4 github.com/pkg/errors v0.9.1 @@ -49,16 +49,17 @@ require ( go.opentelemetry.io/otel/metric v1.37.0 go.opentelemetry.io/otel/sdk v1.37.0 go.opentelemetry.io/otel/sdk/metric v1.37.0 - golang.org/x/oauth2 v0.30.0 - golang.org/x/sync v0.18.0 + golang.org/x/crypto v0.46.0 + golang.org/x/oauth2 v0.34.0 + golang.org/x/sync v0.19.0 google.golang.org/api v0.246.0 google.golang.org/grpc v1.75.0 - k8s.io/api v0.33.2 - k8s.io/apimachinery v0.33.2 - k8s.io/client-go v0.33.2 + k8s.io/api v0.35.0 + k8s.io/apimachinery v0.35.0 + k8s.io/client-go v0.35.0 k8s.io/klog/v2 v2.130.1 - k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 - sigs.k8s.io/controller-runtime v0.21.0 + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 + sigs.k8s.io/controller-runtime v0.22.4 ) require ( @@ -106,12 +107,12 @@ require ( github.com/docker/cli v28.3.0+incompatible // indirect github.com/docker/distribution v2.8.3+incompatible // indirect github.com/docker/docker-credential-helpers v0.9.3 // indirect - github.com/emicklei/go-restful/v3 v3.12.1 // indirect + github.com/emicklei/go-restful/v3 v3.12.2 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/evanphx/json-patch/v5 v5.9.11 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect - github.com/fxamacker/cbor/v2 v2.7.0 // indirect + github.com/fxamacker/cbor/v2 v2.9.0 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.6.2 // indirect github.com/go-git/go-git/v5 v5.16.1 // indirect @@ -120,14 +121,13 @@ require ( github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect - github.com/go-viper/mapstructure/v2 v2.4.0 // indirect + github.com/go-viper/mapstructure/v2 v2.5.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/goccy/go-json v0.10.3 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect - github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/google/btree v1.1.3 // indirect - github.com/google/gnostic-models v0.6.9 // indirect + github.com/google/gnostic-models v0.7.0 // indirect github.com/google/go-containerregistry v0.20.6 // indirect github.com/google/go-github/v73 v73.0.0 // indirect github.com/google/go-querystring v1.1.0 // indirect @@ -165,7 +165,7 @@ require ( github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/moby/spdystream v0.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/muesli/mango v0.2.0 // indirect github.com/muesli/mango-cobra v1.3.0 // indirect github.com/muesli/mango-pflag v0.1.0 // indirect @@ -174,14 +174,15 @@ require ( github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/nais/krakend v0.0.0-20251023101753-7caa0215c6b9 // indirect + github.com/nais/pgrator v0.0.0-20260113113020-3944d387b42d // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect github.com/pjbgf/sha1cd v0.3.2 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/client_golang v1.22.0 // indirect - github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.62.0 // indirect - github.com/prometheus/procfs v0.15.1 // indirect + github.com/prometheus/client_golang v1.23.2 // indirect + github.com/prometheus/client_model v0.6.2 // indirect + github.com/prometheus/common v0.66.1 // indirect + github.com/prometheus/procfs v0.16.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sagikazarmark/locafero v0.12.0 // indirect github.com/securego/gosec/v2 v2.22.10 // indirect @@ -189,11 +190,11 @@ require ( github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect github.com/sethvargo/ratchet v0.11.4 // indirect github.com/shopspring/decimal v1.4.0 // indirect - github.com/sirupsen/logrus v1.9.3 // indirect + github.com/sirupsen/logrus v1.9.4 // indirect github.com/skeema/knownhosts v1.3.1 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/spf13/cast v1.10.0 // indirect - github.com/spf13/cobra v1.10.1 // indirect + github.com/spf13/cobra v1.10.2 // indirect github.com/spf13/pflag v1.0.10 // indirect github.com/spf13/viper v1.21.0 // indirect github.com/stretchr/objx v0.5.2 // indirect @@ -222,34 +223,34 @@ require ( go.opentelemetry.io/proto/otlp v1.7.0 // indirect go.uber.org/multierr v1.11.0 // indirect 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/crypto v0.45.0 // indirect golang.org/x/exp/typeparams v0.0.0-20250210185358-939b2ce775ac // indirect - golang.org/x/mod v0.30.0 // indirect - golang.org/x/net v0.47.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54 // indirect - golang.org/x/term v0.37.0 // indirect - golang.org/x/text v0.31.0 // indirect - golang.org/x/time v0.12.0 // indirect - golang.org/x/tools v0.39.0 // indirect + golang.org/x/mod v0.31.0 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc // indirect + golang.org/x/term v0.38.0 // indirect + golang.org/x/text v0.32.0 // indirect + golang.org/x/time v0.14.0 // indirect + golang.org/x/tools v0.40.0 // indirect golang.org/x/vuln v1.1.4 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/genai v1.30.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c // indirect - google.golang.org/protobuf v1.36.8 // indirect - gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect + google.golang.org/protobuf v1.36.11 // indirect + gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect honnef.co/go/tools v0.6.1 // indirect - k8s.io/apiextensions-apiserver v0.33.0 // indirect - k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect + k8s.io/apiextensions-apiserver v0.35.0 // indirect + k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect mvdan.cc/gofumpt v0.9.2 // indirect - sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect - sigs.k8s.io/yaml v1.4.0 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect + sigs.k8s.io/yaml v1.6.0 // indirect ) diff --git a/go.sum b/go.sum index 0d3e46d4..55a1ff56 100644 --- a/go.sum +++ b/go.sum @@ -89,8 +89,6 @@ 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/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb h1:m935MPodAbYS46DG4pJSv7WO+VECIWUQ7OJYSoTrMh4= github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI= -github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= -github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/bmatcuk/doublestar/v4 v4.8.1 h1:54Bopc5c2cAvhLRAzqOGCYHYyhcDHsFF4wWIR5wKP38= github.com/bmatcuk/doublestar/v4 v4.8.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/bradleyjkemp/cupaloy/v2 v2.6.0 h1:knToPYa2xtfg42U3I6punFEjaGFKWQRXJwj0JTv4mTs= @@ -148,8 +146,8 @@ github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqI github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo= github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o= github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE= -github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU= -github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU= +github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -166,8 +164,8 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= -github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= -github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/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/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU= github.com/go-chi/chi/v5 v5.2.2 h1:CMwsvRVTbXVytCk1Wd72Zy1LAsAh9GxMmSNWLHCG618= @@ -202,8 +200,8 @@ github.com/go-sql-driver/mysql v1.9.2/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI6 github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= 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.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= -github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= +github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= @@ -212,8 +210,6 @@ 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/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= @@ -236,8 +232,8 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= 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.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw= -github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw= +github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= +github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= github.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786 h1:rcv+Ippz6RAtvaGgKxc+8FQIpxHgsF+HBzPyYL2cyVU= github.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786/go.mod h1:apVn/GCasLZUVpAJ6oWAuyP7Ne7CEsQbTnc0plM3m+o= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -247,7 +243,6 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-containerregistry v0.20.6 h1:cvWX87UxxLgaH76b4hIvya6Dzz9qHB31qAwjAohdSTU= @@ -336,8 +331,6 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= -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/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= @@ -400,8 +393,9 @@ github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVO 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= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/muesli/mango v0.2.0 h1:iNNc0c5VLQ6fsMgAqGQofByNUBH2Q2nEbD6TaI+5yyQ= github.com/muesli/mango v0.2.0/go.mod h1:5XFpbC8jY5UUv89YQciiXNlbi+iJgt29VDC5xbzrLL4= github.com/muesli/mango-cobra v1.3.0 h1:vQy5GvPg3ndOSpduxutqFoINhWk3vD5K2dXo5E8pqec= @@ -424,14 +418,16 @@ github.com/nais/krakend v0.0.0-20251023101753-7caa0215c6b9 h1:+FXD+P7Z45/sbzgsPB github.com/nais/krakend v0.0.0-20251023101753-7caa0215c6b9/go.mod h1:GB1VfSnXR1+Ijn38TYNVjdKCe84Fah3WaYQwnFne5DI= github.com/nais/krakend/pkg/migration v0.0.0-20251112211103-82b954ae962b h1:DQcbwlMyEt3z4rWLzMYPRDCVrCaxQpVXFzQosgObhKo= github.com/nais/krakend/pkg/migration v0.0.0-20251112211103-82b954ae962b/go.mod h1:Siwxo1B39dMTFYEwTzPwr1+Rg5r/0OAtHC3BbKh/XPA= -github.com/nais/liberator v0.0.0-20251105145237-b406841758d4 h1:fxZoiKz7BUzSxTxWcfrdL9EloF8Fv96gFaZFst9efbA= -github.com/nais/liberator v0.0.0-20251105145237-b406841758d4/go.mod h1:p6EA7AKqzH798N7yvG8GDHVMzzkpORoxoyfcFz5Oa7c= +github.com/nais/liberator v0.0.0-20260128091017-350fb9813ed9 h1:OcbWh2vfB0oQWffpXtakRyZbMOcFUIrzRpYHEgGRM1w= +github.com/nais/liberator v0.0.0-20260128091017-350fb9813ed9/go.mod h1:ec6FGHkMkSIWh2UnspPLq7uQrrZvAaUacVXUf4bBR1s= github.com/nais/naistrix v0.17.0 h1:VpklcAgBaPoANOtMocf7zcULYlng+C08wYjJkNijTqA= github.com/nais/naistrix v0.17.0/go.mod h1:MWCKqnuDcVYHG6qZz4nyRYrw+ax/QO6NzxExMat/btc= -github.com/onsi/ginkgo/v2 v2.26.0 h1:1J4Wut1IlYZNEAWIV3ALrT9NfiaGW2cDCJQSFQMs/gE= -github.com/onsi/ginkgo/v2 v2.26.0/go.mod h1:qhEywmzWTBUY88kfO0BRvX4py7scov9yR+Az2oavUzw= -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/nais/pgrator v0.0.0-20260113113020-3944d387b42d h1:Ciq0quRhHOeeOTWy9WNmLe04uNYhe7l9qIrFTpFC5y0= +github.com/nais/pgrator v0.0.0-20260113113020-3944d387b42d/go.mod h1:jpksYq94zmmjIIhjOBl+9GpEkTbaeLrrcINPQx9REx4= +github.com/onsi/ginkgo/v2 v2.27.3 h1:ICsZJ8JoYafeXFFlFAG75a7CxMsJHwgKwtO+82SE9L8= +github.com/onsi/ginkgo/v2 v2.27.3/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo= +github.com/onsi/gomega v1.39.0 h1:y2ROC3hKFmQZJNFeGAMeHZKkjBL65mIZcvrLQBF9k6Q= +github.com/onsi/gomega v1.39.0/go.mod h1:ZCU1pkQcXDO5Sl9/VVEGlDyp+zm0m1cmeG5TOzLgdh4= 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.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= @@ -445,15 +441,15 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE 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/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= -github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= +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.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= -github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= -github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= -github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= -github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= +github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs= +github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA= +github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= +github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= github.com/pterm/pterm v0.12.27/go.mod h1:PhQ89w4i95rhgE+xedAoqous6K9X+r6aSOI2eFF7DZI= github.com/pterm/pterm v0.12.29/go.mod h1:WI3qxgvoQFFGKGjGnJR849gU0TsEOvKn5Q8LlY1U7lg= github.com/pterm/pterm v0.12.30/go.mod h1:MOqLIyMOgmTDz9yorcYbcw+HsgoZo3BQfg2wtl3HEFE= @@ -491,8 +487,8 @@ github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= +github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8= github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY= github.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGByCY= @@ -503,8 +499,8 @@ github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= -github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= -github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= +github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= +github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -567,8 +563,6 @@ github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavM github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4= github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4= -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= github.com/zalando/go-keyring v0.2.6 h1:r7Yc3+H+Ux0+M72zacZoItR3UDxeWfKTcabvkI8ua9s= github.com/zalando/go-keyring v0.2.6/go.mod h1:2TCrxYrbUNYfNS/Kgy/LSrkSQzZ5UPVH85RwfczwvcI= @@ -600,23 +594,22 @@ go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mx go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= go.opentelemetry.io/proto/otlp v1.7.0 h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os= go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo= -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= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= +go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= 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/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= -golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw= golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM= @@ -625,39 +618,33 @@ golang.org/x/exp/typeparams v0.0.0-20250210185358-939b2ce775ac/go.mod h1:AbB0pIl golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -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.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= -golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= +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-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 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.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 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.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= -golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-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.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-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 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= @@ -675,39 +662,37 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/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/telemetry v0.0.0-20251111182119-bc8e575c7b54 h1:E2/AqCUMZGgd73TQkxUMcMla25GB9i/5HOdLr+uH7Vo= -golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc h1:bH6xUXay0AIFMElXG2rQ4uiE+7ncwtiOdPfYK1NK2XA= +golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ= 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.6/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/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= -golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +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-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 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.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.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +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/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM= golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM= @@ -715,9 +700,7 @@ golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated/go.mod h1:RVAQXBGN golang.org/x/vuln v1.1.4 h1:Ju8QsuyhX3Hk8ma3CesTbO8vfJD9EvUBgHvkxHBzj0I= golang.org/x/vuln v1.1.4/go.mod h1:F+45wmU18ym/ca5PLTPLsSzr2KppzswxPP603ldA67s= 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= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= @@ -753,14 +736,14 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc= -google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= +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/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= -gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= +gopkg.in/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= +gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= @@ -779,30 +762,29 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.6.1 h1:R094WgE8K4JirYjBaOpz/AvTyUu/3wbmAoskKN/pxTI= honnef.co/go/tools v0.6.1/go.mod h1:3puzxxljPCe8RGJX7BIy1plGbxEOZni5mR2aXe3/uk4= -k8s.io/api v0.33.2 h1:YgwIS5jKfA+BZg//OQhkJNIfie/kmRsO0BmNaVSimvY= -k8s.io/api v0.33.2/go.mod h1:fhrbphQJSM2cXzCWgqU29xLDuks4mu7ti9vveEnpSXs= -k8s.io/apiextensions-apiserver v0.33.0 h1:d2qpYL7Mngbsc1taA4IjJPRJ9ilnsXIrndH+r9IimOs= -k8s.io/apiextensions-apiserver v0.33.0/go.mod h1:VeJ8u9dEEN+tbETo+lFkwaaZPg6uFKLGj5vyNEwwSzc= -k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY= -k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= -k8s.io/client-go v0.33.2 h1:z8CIcc0P581x/J1ZYf4CNzRKxRvQAwoAolYPbtQes+E= -k8s.io/client-go v0.33.2/go.mod h1:9mCgT4wROvL948w6f6ArJNb7yQd7QsvqavDeZHvNmHo= +k8s.io/api v0.35.0 h1:iBAU5LTyBI9vw3L5glmat1njFK34srdLmktWwLTprlY= +k8s.io/api v0.35.0/go.mod h1:AQ0SNTzm4ZAczM03QH42c7l3bih1TbAXYo0DkF8ktnA= +k8s.io/apiextensions-apiserver v0.35.0 h1:3xHk2rTOdWXXJM+RDQZJvdx0yEOgC0FgQ1PlJatA5T4= +k8s.io/apiextensions-apiserver v0.35.0/go.mod h1:E1Ahk9SADaLQ4qtzYFkwUqusXTcaV2uw3l14aqpL2LU= +k8s.io/apimachinery v0.35.0 h1:Z2L3IHvPVv/MJ7xRxHEtk6GoJElaAqDCCU0S6ncYok8= +k8s.io/apimachinery v0.35.0/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns= +k8s.io/client-go v0.35.0 h1:IAW0ifFbfQQwQmga0UdoH0yvdqrbwMdq9vIFEhRpxBE= +k8s.io/client-go v0.35.0/go.mod h1:q2E5AAyqcbeLGPdoRB+Nxe3KYTfPce1Dnu1myQdqz9o= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4= -k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8= -k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y= -k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE= +k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= mvdan.cc/gofumpt v0.9.2 h1:zsEMWL8SVKGHNztrx6uZrXdp7AX8r421Vvp23sz7ik4= mvdan.cc/gofumpt v0.9.2/go.mod h1:iB7Hn+ai8lPvofHd9ZFGVg2GOr8sBUw1QUWjNbmIL/s= -sigs.k8s.io/controller-runtime v0.21.0 h1:CYfjpEuicjUecRk+KAeyYh+ouUBn4llGyDYytIGcJS8= -sigs.k8s.io/controller-runtime v0.21.0/go.mod h1:OSg14+F65eWqIu4DceX7k/+QRAbTTvxeQSNSOQpukWM= -sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= -sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= -sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/controller-runtime v0.22.4 h1:GEjV7KV3TY8e+tJ2LCTxUTanW4z/FmNB7l327UfMq9A= +sigs.k8s.io/controller-runtime v0.22.4/go.mod h1:+QX1XUpTXN4mLoblf4tqr5CQcyHPAki2HLXqQMY6vh8= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= -sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= -sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= +sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco= +sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= +sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/internal/aiven/aiven_services/stream.go b/internal/aiven/aiven_services/stream.go new file mode 100644 index 00000000..f49dc87a --- /dev/null +++ b/internal/aiven/aiven_services/stream.go @@ -0,0 +1,28 @@ +package aiven_services + +import ( + kafka_nais_io_v1 "github.com/nais/liberator/pkg/apis/kafka.nais.io/v1" +) + +type Stream struct { + Pool KafkaPool + StreamPrefix string + AdditionalUsers []string +} + +func (s *Stream) Name() string { + return s.StreamPrefix +} + +func (s *Stream) Setup(setup *ServiceSetup) { + s.Pool = setup.Pool +} + +func (s *Stream) Apply(streamSpec *kafka_nais_io_v1.StreamSpec, _ string) { + streamSpec.Pool = s.Pool.String() + // streamSpec.AdditionalUsers = append(streamSpec.AdditionalUsers, TODO) +} + +func (s *Stream) Is(other Service) bool { + return s.Name() == other.Name() +} diff --git a/internal/aiven/command/aiven.go b/internal/aiven/command/aiven.go index 01260bf4..3f30c895 100644 --- a/internal/aiven/command/aiven.go +++ b/internal/aiven/command/aiven.go @@ -16,6 +16,7 @@ func Aiven(parentFlags *flags.GlobalFlags) *naistrix.Command { create(aivenFlags), get(aivenFlags), tidy(aivenFlags), + grantAccess(aivenFlags), }, } } diff --git a/internal/aiven/command/create.go b/internal/aiven/command/create.go index 64db157b..f3ced7fe 100644 --- a/internal/aiven/command/create.go +++ b/internal/aiven/command/create.go @@ -25,6 +25,7 @@ func create(parentFlags *flag.Aiven) *naistrix.Command { SubCommands: []*naistrix.Command{ createKafka(createFlags), createOpenSearch(createFlags), + createStream(createFlags), }, } } diff --git a/internal/aiven/command/create_kafka.go b/internal/aiven/command/create_kafka.go index 7da4e886..819bf99a 100644 --- a/internal/aiven/command/create_kafka.go +++ b/internal/aiven/command/create_kafka.go @@ -53,7 +53,6 @@ func createKafka(parentFlags *flag.Create) *naistrix.Command { if err != nil { metric.CreateAndIncreaseCounter(ctx, "aiven_create_generating_aivenapplication_error_total") return fmt.Errorf("an error occurred generating 'AivenApplication': %v", err) - } out.Printf("Use the following command to generate configuration secrets:\n\tnais aiven get %v %v %v\n", service.Name(), aivenApp.Spec.Kafka.SecretName, aivenApp.Namespace) diff --git a/internal/aiven/command/create_stream.go b/internal/aiven/command/create_stream.go new file mode 100644 index 00000000..33ebad54 --- /dev/null +++ b/internal/aiven/command/create_stream.go @@ -0,0 +1,53 @@ +package command + +import ( + "context" + "fmt" + "strings" + + "github.com/nais/cli/internal/aiven" + "github.com/nais/cli/internal/aiven/aiven_services" + "github.com/nais/cli/internal/aiven/command/flag" + "github.com/nais/cli/internal/k8s" + "github.com/nais/cli/internal/metric" + "github.com/nais/naistrix" +) + +func createStream(parentFlags *flag.Create) *naistrix.Command { + createStreamFlags := &flag.CreateStream{Create: parentFlags, Pool: "nav-dev"} + + return &naistrix.Command{ + Name: "stream", + Title: "Grant a user access to a Kafka Stream.", + Flags: createStreamFlags, + Args: []naistrix.Argument{ + {Name: "stream-name"}, + {Name: "username"}, + }, + RunFunc: func(ctx context.Context, args *naistrix.Arguments, out *naistrix.OutputWriter) error { + pool, err := aiven_services.KafkaPoolFromString(createStreamFlags.Pool) + if err != nil { + return fmt.Errorf("valid values for pool should specify tenant and environment separated by a dash (-): %v", err) + } + + streamSplit := strings.Split(args.Get("stream-name"), ".") + if len(streamSplit) < 2 { + return fmt.Errorf("Name of stream does not follow expected `._stream_*` prefix: %v", args.Get("stream-name")) + } + namespace := streamSplit[0] + + if createStreamFlags.Secret == "" { + if createStreamFlags.Secret, err = aiven.CreateSecretName(args.Get("username"), namespace); err != nil { + return fmt.Errorf("creating secret name: %v", err) + } + } + + // service := &aiven_services.Kafka{} + // TODO: get the Stream's CRD, and add username to `additionalUsers` list + client := k8s.SetupControllerRuntimeClient() + client.Client.Get(ctx, objectKey, object) + + return nil + }, + } +} diff --git a/internal/aiven/command/flag/flag.go b/internal/aiven/command/flag/flag.go index f25a940c..cfd7c122 100644 --- a/internal/aiven/command/flag/flag.go +++ b/internal/aiven/command/flag/flag.go @@ -21,3 +21,12 @@ type CreateOpenSearch struct { Instance string `name:"instance" short:"i" usage:"The name of the OpenSearch |INSTANCE|."` Access string `name:"access" short:"a" usage:"The access |LEVEL|."` } + +type GrantAccess struct { + *Aiven +} + +type GrantAccessStream struct { + *GrantAccess + Namespace string `namespace:"namespace" short:"n" usage:"|NAMESPACE| of the Stream.kafka.nais.io's |NAMESPACE|."` +} diff --git a/internal/aiven/command/grant_access.go b/internal/aiven/command/grant_access.go new file mode 100644 index 00000000..b5b1e033 --- /dev/null +++ b/internal/aiven/command/grant_access.go @@ -0,0 +1,19 @@ +package command + +import ( + "github.com/nais/cli/internal/aiven/command/flag" + "github.com/nais/naistrix" +) + +func grantAccess(parentFlags *flag.Aiven) *naistrix.Command { + grantAccessFlags := &flag.GrantAccess{Aiven: parentFlags} + + return &naistrix.Command{ + Name: "grant-access", + Title: "Grant a user access to an Aiven service.", + StickyFlags: grantAccessFlags, + SubCommands: []*naistrix.Command{ + grantAccessStream(grantAccessFlags), + }, + } +} diff --git a/internal/aiven/command/grant_access_stream.go b/internal/aiven/command/grant_access_stream.go new file mode 100644 index 00000000..71384dad --- /dev/null +++ b/internal/aiven/command/grant_access_stream.go @@ -0,0 +1,60 @@ +package command + +import ( + "context" + "fmt" + + "github.com/nais/cli/internal/aiven/command/flag" + "github.com/nais/cli/internal/k8s" + nais_kafka "github.com/nais/liberator/pkg/apis/kafka.nais.io/v1" + "github.com/nais/naistrix" + v1 "k8s.io/api/core/v1" + ctrl "sigs.k8s.io/controller-runtime/pkg/client" +) + +func grantAccessStream(parentFlags *flag.GrantAccess) *naistrix.Command { + grantAccessStreamFlags := &flag.GrantAccessStream{GrantAccess: parentFlags} + + return &naistrix.Command{ + Name: "stream", + Title: "Grant a user's service-user access to a Kafka Stream.", + Flags: grantAccessStreamFlags, + Args: []naistrix.Argument{ + {Name: "user-name"}, + {Name: "stream-name"}, + }, + RunFunc: func(ctx context.Context, args *naistrix.Arguments, out *naistrix.OutputWriter) error { + client := k8s.SetupControllerRuntimeClient() + + var namespace v1.Namespace + if err := client.Get(ctx, ctrl.ObjectKey{Name: args.Get("namespace")}, &namespace); err != nil { + return fmt.Errorf("validate namespace: %w", err) + } + + var stream nais_kafka.Stream + if err := client.Get(ctx, ctrl.ObjectKey{Name: args.Get("stream-name")}, &stream); err != nil { + return fmt.Errorf("validate stream: %w", err) + } + + userName := args.Get("username") + for _, user := range stream.Spec.AdditionalUsers { + if user.Username == userName { + out.Printf("Username '%s' already listed in Stream '%s/%s''s ACLs.", userName, &namespace.Name, stream.Name) + return nil + } + } + + stream.Spec.AdditionalUsers = append(stream.Spec.AdditionalUsers, nais_kafka.AdditionalStreamUser{ + Username: userName, + }) + err := client.Update(ctx, &stream) + if err != nil { + return err + } + + out.Printf("Username '%s' added to Stream '%s/%s' ACLs.", userName, &namespace.Name, stream.Name) + + return nil + }, + } +} From 8be75d147e31530ca13a6a5bd70d3f8acee1f5ef Mon Sep 17 00:00:00 2001 From: "@x10an14-nav" Date: Wed, 28 Jan 2026 12:55:02 +0100 Subject: [PATCH 2/5] reformat: flatten if-else --- .envrc | 3 +++ flake.lock | 26 +++++++++++++++++++++ flake.nix | 52 +++++++++++++++++++++++++++++++++++++++++ internal/aiven/aiven.go | 27 ++++++++++----------- 4 files changed, 95 insertions(+), 13 deletions(-) create mode 100644 .envrc create mode 100644 flake.lock create mode 100644 flake.nix diff --git a/.envrc b/.envrc new file mode 100644 index 00000000..131d0904 --- /dev/null +++ b/.envrc @@ -0,0 +1,3 @@ +if nix flake show &> /dev/null; then + use flake +fi diff --git a/flake.lock b/flake.lock new file mode 100644 index 00000000..3684841f --- /dev/null +++ b/flake.lock @@ -0,0 +1,26 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1769461804, + "narHash": "sha256-msG8SU5WsBUfVVa/9RPLaymvi5bI8edTavbIq3vRlhI=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "bfc1b8a4574108ceef22f02bafcf6611380c100d", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "ref": "nixos-unstable", + "type": "indirect" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 00000000..4bf175e5 --- /dev/null +++ b/flake.nix @@ -0,0 +1,52 @@ +{ + description = "Kafkarator"; + + inputs.nixpkgs.url = "nixpkgs/nixos-unstable"; + + outputs = { nixpkgs, ... }: + let + goOverlay = final: prev: let + version = "1.25.5"; + newerGoVersion = prev.go.overrideAttrs (old: { + inherit version; + src = prev.fetchurl { + url = "https://go.dev/dl/go${version}.src.tar.gz"; + hash = ""; # TODO: if `version` is changed in the future + }; + }); + nixpkgsVersion = prev.go.version; + newVersionNotInNixpkgs = -1 == builtins.compareVersions nixpkgsVersion version; + in { + go = if newVersionNotInNixpkgs then newerGoVersion else prev.go; + buildGoModule = prev.buildGoModule.override { go = final.go; }; + }; + # helpers + withSystem = nixpkgs.lib.genAttrs [ + "x86_64-linux" + "x86_64-darwin" + "aarch64-linux" + "aarch64-darwin" + ]; + withPkgs = f: + withSystem (system: + f (import nixpkgs { + inherit system; + overlays = [ goOverlay ]; + })); + in { + devShells = withPkgs (pkgs: { + default = pkgs.mkShell { + buildInputs = with pkgs; [ + gnumake + go + golangci-lint-langserver + gopls + python3 + python3Packages.python-lsp-server + black + ]; + }; + }); + formatter = withPkgs (pkgs: pkgs.nixfmt-rfc-style); + }; +} diff --git a/internal/aiven/aiven.go b/internal/aiven/aiven.go index a6735357..48a96639 100644 --- a/internal/aiven/aiven.go +++ b/internal/aiven/aiven.go @@ -95,23 +95,24 @@ func (a Aiven) createOrUpdate(aivenApp *aiven_nais_io_v1.AivenApplication, out * if err != nil { if k8serrors.IsNotFound(err) { err = a.Client.Create(a.Ctx, aivenApp) - if err != nil { - return err + if err == nil { + out.Printf("AivenApplication: '%v' created.", aivenApp.Name) } - out.Printf("AivenApplication: '%v' created.", aivenApp.Name) - } - } else { - if len(existingAivenApp.GetObjectMeta().GetOwnerReferences()) > 0 { - return fmt.Errorf("username '%s' is owned by another resource; overwrite is not allowed", a.Properties.Username) - } - - aivenApp.SetResourceVersion(existingAivenApp.GetResourceVersion()) - err = a.Client.Update(a.Ctx, aivenApp) - if err != nil { return err } - out.Printf("AivenApplication: '%v' updated.", aivenApp.Name) + return err + } + + if len(existingAivenApp.GetObjectMeta().GetOwnerReferences()) > 0 { + return fmt.Errorf("username '%s' is owned by another resource; overwrite is not allowed", a.Properties.Username) + } + + aivenApp.SetResourceVersion(existingAivenApp.GetResourceVersion()) + err = a.Client.Update(a.Ctx, aivenApp) + if err != nil { + return err } + out.Printf("AivenApplication: '%v' updated.", aivenApp.Name) return nil } From d081bdd3a9f074970283683667b970f530ffd220 Mon Sep 17 00:00:00 2001 From: Youssef Bel Mekki <38552193+ybelMekk@users.noreply.github.com> Date: Thu, 29 Jan 2026 09:13:47 +0100 Subject: [PATCH 3/5] feat(aiven): add commands to grant access to Kafka streams and topics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * migratorBuilder usage Co-authored-by: Sindre Rødseth Hansen Co-authored-by: @x10an14-nav --- internal/aiven/command/create.go | 1 - internal/aiven/command/create_stream.go | 53 -------- internal/aiven/command/flag/flag.go | 5 +- internal/aiven/command/grant_access.go | 1 + internal/aiven/command/grant_access_stream.go | 43 ++----- internal/aiven/command/grant_access_topic.go | 51 ++++++++ internal/aiven/grant_access.go | 117 ++++++++++++++++++ internal/postgres/migrate/setup_test.go | 43 ++++--- 8 files changed, 205 insertions(+), 109 deletions(-) delete mode 100644 internal/aiven/command/create_stream.go create mode 100644 internal/aiven/command/grant_access_topic.go create mode 100644 internal/aiven/grant_access.go diff --git a/internal/aiven/command/create.go b/internal/aiven/command/create.go index f3ced7fe..64db157b 100644 --- a/internal/aiven/command/create.go +++ b/internal/aiven/command/create.go @@ -25,7 +25,6 @@ func create(parentFlags *flag.Aiven) *naistrix.Command { SubCommands: []*naistrix.Command{ createKafka(createFlags), createOpenSearch(createFlags), - createStream(createFlags), }, } } diff --git a/internal/aiven/command/create_stream.go b/internal/aiven/command/create_stream.go deleted file mode 100644 index 33ebad54..00000000 --- a/internal/aiven/command/create_stream.go +++ /dev/null @@ -1,53 +0,0 @@ -package command - -import ( - "context" - "fmt" - "strings" - - "github.com/nais/cli/internal/aiven" - "github.com/nais/cli/internal/aiven/aiven_services" - "github.com/nais/cli/internal/aiven/command/flag" - "github.com/nais/cli/internal/k8s" - "github.com/nais/cli/internal/metric" - "github.com/nais/naistrix" -) - -func createStream(parentFlags *flag.Create) *naistrix.Command { - createStreamFlags := &flag.CreateStream{Create: parentFlags, Pool: "nav-dev"} - - return &naistrix.Command{ - Name: "stream", - Title: "Grant a user access to a Kafka Stream.", - Flags: createStreamFlags, - Args: []naistrix.Argument{ - {Name: "stream-name"}, - {Name: "username"}, - }, - RunFunc: func(ctx context.Context, args *naistrix.Arguments, out *naistrix.OutputWriter) error { - pool, err := aiven_services.KafkaPoolFromString(createStreamFlags.Pool) - if err != nil { - return fmt.Errorf("valid values for pool should specify tenant and environment separated by a dash (-): %v", err) - } - - streamSplit := strings.Split(args.Get("stream-name"), ".") - if len(streamSplit) < 2 { - return fmt.Errorf("Name of stream does not follow expected `._stream_*` prefix: %v", args.Get("stream-name")) - } - namespace := streamSplit[0] - - if createStreamFlags.Secret == "" { - if createStreamFlags.Secret, err = aiven.CreateSecretName(args.Get("username"), namespace); err != nil { - return fmt.Errorf("creating secret name: %v", err) - } - } - - // service := &aiven_services.Kafka{} - // TODO: get the Stream's CRD, and add username to `additionalUsers` list - client := k8s.SetupControllerRuntimeClient() - client.Client.Get(ctx, objectKey, object) - - return nil - }, - } -} diff --git a/internal/aiven/command/flag/flag.go b/internal/aiven/command/flag/flag.go index cfd7c122..1bb1b702 100644 --- a/internal/aiven/command/flag/flag.go +++ b/internal/aiven/command/flag/flag.go @@ -24,9 +24,10 @@ type CreateOpenSearch struct { type GrantAccess struct { *Aiven + Access string `name:"access" short:"x" usage:"Access |LEVEL| (readwrite, read and write)."` } -type GrantAccessStream struct { +type GrantAccessCommon struct { *GrantAccess - Namespace string `namespace:"namespace" short:"n" usage:"|NAMESPACE| of the Stream.kafka.nais.io's |NAMESPACE|."` + Namespace string `name:"namespace" short:"n" usage:"|NAMESPACE| of the Stream.kafka.nais.io's |NAMESPACE|."` } diff --git a/internal/aiven/command/grant_access.go b/internal/aiven/command/grant_access.go index b5b1e033..864ccde7 100644 --- a/internal/aiven/command/grant_access.go +++ b/internal/aiven/command/grant_access.go @@ -14,6 +14,7 @@ func grantAccess(parentFlags *flag.Aiven) *naistrix.Command { StickyFlags: grantAccessFlags, SubCommands: []*naistrix.Command{ grantAccessStream(grantAccessFlags), + grantAccessTopic(grantAccessFlags), }, } } diff --git a/internal/aiven/command/grant_access_stream.go b/internal/aiven/command/grant_access_stream.go index 71384dad..dc434627 100644 --- a/internal/aiven/command/grant_access_stream.go +++ b/internal/aiven/command/grant_access_stream.go @@ -2,58 +2,39 @@ package command import ( "context" - "fmt" + "github.com/nais/cli/internal/aiven" "github.com/nais/cli/internal/aiven/command/flag" - "github.com/nais/cli/internal/k8s" - nais_kafka "github.com/nais/liberator/pkg/apis/kafka.nais.io/v1" "github.com/nais/naistrix" - v1 "k8s.io/api/core/v1" - ctrl "sigs.k8s.io/controller-runtime/pkg/client" ) func grantAccessStream(parentFlags *flag.GrantAccess) *naistrix.Command { - grantAccessStreamFlags := &flag.GrantAccessStream{GrantAccess: parentFlags} + grantAccessStreamFlags := &flag.GrantAccessCommon{GrantAccess: parentFlags} return &naistrix.Command{ Name: "stream", Title: "Grant a user's service-user access to a Kafka Stream.", Flags: grantAccessStreamFlags, Args: []naistrix.Argument{ - {Name: "user-name"}, - {Name: "stream-name"}, + {Name: "username"}, + {Name: "stream"}, }, RunFunc: func(ctx context.Context, args *naistrix.Arguments, out *naistrix.OutputWriter) error { - client := k8s.SetupControllerRuntimeClient() - - var namespace v1.Namespace - if err := client.Get(ctx, ctrl.ObjectKey{Name: args.Get("namespace")}, &namespace); err != nil { - return fmt.Errorf("validate namespace: %w", err) - } - - var stream nais_kafka.Stream - if err := client.Get(ctx, ctrl.ObjectKey{Name: args.Get("stream-name")}, &stream); err != nil { - return fmt.Errorf("validate stream: %w", err) - } - + namespace := args.Get("namespace") userName := args.Get("username") - for _, user := range stream.Spec.AdditionalUsers { - if user.Username == userName { - out.Printf("Username '%s' already listed in Stream '%s/%s''s ACLs.", userName, &namespace.Name, stream.Name) - return nil - } - } + stream := args.Get("stream") - stream.Spec.AdditionalUsers = append(stream.Spec.AdditionalUsers, nais_kafka.AdditionalStreamUser{ - Username: userName, - }) - err := client.Update(ctx, &stream) + accessResult, err := aiven.GrantAccessToStream(ctx, namespace, stream, userName) if err != nil { return err } - out.Printf("Username '%s' added to Stream '%s/%s' ACLs.", userName, &namespace.Name, stream.Name) + if !accessResult.Added { + out.Printf("Username '%s' already listed in Stream '%s/%s' ACLs.", userName, namespace, stream) + return nil + } + out.Printf("Username '%s' added to Stream '%s/%s' ACLs.", userName, namespace, stream) return nil }, } diff --git a/internal/aiven/command/grant_access_topic.go b/internal/aiven/command/grant_access_topic.go new file mode 100644 index 00000000..6e4e17d6 --- /dev/null +++ b/internal/aiven/command/grant_access_topic.go @@ -0,0 +1,51 @@ +package command + +import ( + "context" + + "github.com/nais/cli/internal/aiven" + "github.com/nais/cli/internal/aiven/command/flag" + nais_kafka "github.com/nais/liberator/pkg/apis/kafka.nais.io/v1" + "github.com/nais/naistrix" +) + +func grantAccessTopic(parentFlags *flag.GrantAccess) *naistrix.Command { + grantAccessTopicFlags := &flag.GrantAccessCommon{GrantAccess: parentFlags} + + return &naistrix.Command{ + Name: "topic", + Title: "Grant a user's service-user access to a Kafka Topic.", + Flags: grantAccessTopicFlags, + Args: []naistrix.Argument{ + {Name: "username"}, + {Name: "topic"}, + }, + RunFunc: func(ctx context.Context, args *naistrix.Arguments, out *naistrix.OutputWriter) error { + namespace := args.Get("namespace") + topicName := args.Get("topic") + + acl := nais_kafka.TopicACL{ + Team: namespace, + Application: args.Get("username"), + Access: args.Get("access"), + } + + accessResult, err := aiven.GrantAccessToTopic(ctx, namespace, topicName, acl) + if err != nil { + return err + } + + if !accessResult.Added { + out.Printf("ACL already exists for team '%s', application '%s', access '%s' on topic '%s/%s'.", + acl.Team, acl.Application, acl.Access, namespace, topicName, + ) + return nil + } + + out.Printf("ACL added for team '%s', application '%s', access '%s' on topic '%s/%s'.", + acl.Team, acl.Application, acl.Access, namespace, topicName, + ) + return nil + }, + } +} diff --git a/internal/aiven/grant_access.go b/internal/aiven/grant_access.go new file mode 100644 index 00000000..6ac70a12 --- /dev/null +++ b/internal/aiven/grant_access.go @@ -0,0 +1,117 @@ +package aiven + +import ( + "context" + "fmt" + + "github.com/nais/cli/internal/k8s" + nais_kafka "github.com/nais/liberator/pkg/apis/kafka.nais.io/v1" + ctrl "sigs.k8s.io/controller-runtime/pkg/client" +) + +type GrantAccessResult struct { + Added bool + Namespace string + Name string + Kind string + Detail string +} + +func GrantAccessToTopic(ctx context.Context, namespace, topicName string, acl nais_kafka.TopicACL) (*GrantAccessResult, error) { + client := k8s.SetupControllerRuntimeClient() + + if err := validateNamespace(ctx, client, namespace); err != nil { + return nil, err + } + + var topic nais_kafka.Topic + if err := client.Get(ctx, ctrl.ObjectKey{Name: topicName, Namespace: namespace}, &topic); err != nil { + return nil, fmt.Errorf("validate topic: %w", err) + } + + // Default to read access if not specified + if acl.Access == "" { + acl.Access = "read" + } + + newACLs, added := ensureTopicACL(topic.Spec.ACL, acl) + if !added { + return &GrantAccessResult{ + Added: false, + Namespace: namespace, + Name: topic.Name, + Kind: topic.Kind, + Detail: acl.Access, + }, nil + } + + topic.Spec.ACL = newACLs + + if err := client.Update(ctx, &topic); err != nil { + return nil, fmt.Errorf("update topic: %w", err) + } + + return &GrantAccessResult{ + Added: true, + Namespace: namespace, + Name: topic.Name, + Kind: topic.Kind, + Detail: acl.Access, + }, nil +} + +func GrantAccessToStream(ctx context.Context, namespace, streamName, userName string) (*GrantAccessResult, error) { + client := k8s.SetupControllerRuntimeClient() + + if err := validateNamespace(ctx, client, namespace); err != nil { + return nil, err + } + + var stream nais_kafka.Stream + if err := client.Get(ctx, ctrl.ObjectKey{Name: streamName, Namespace: namespace}, &stream); err != nil { + return nil, fmt.Errorf("validate stream: %w", err) + } + + newUsers, added := ensureAdditionalStreamUser(stream.Spec.AdditionalUsers, userName) + if !added { + return &GrantAccessResult{ + Added: false, + Namespace: namespace, + Name: stream.Name, + Kind: stream.Kind, + Detail: userName, + }, nil + } + + stream.Spec.AdditionalUsers = newUsers + + if err := client.Update(ctx, &stream); err != nil { + return nil, fmt.Errorf("update stream: %w", err) + } + + return &GrantAccessResult{ + Added: true, + Namespace: namespace, + Name: stream.Name, + Kind: stream.Kind, + Detail: userName, + }, nil +} + +func ensureTopicACL(existing []nais_kafka.TopicACL, wanted nais_kafka.TopicACL) ([]nais_kafka.TopicACL, bool) { + for _, e := range existing { + if e.Team == wanted.Team && e.Application == wanted.Application && e.Access == wanted.Access { + return existing, false + } + } + return append(existing, wanted), true +} + +func ensureAdditionalStreamUser(existing []nais_kafka.AdditionalStreamUser, userName string) ([]nais_kafka.AdditionalStreamUser, bool) { + for _, u := range existing { + if u.Username == userName { + return existing, false + } + } + return append(existing, nais_kafka.AdditionalStreamUser{Username: userName}), true +} diff --git a/internal/postgres/migrate/setup_test.go b/internal/postgres/migrate/setup_test.go index 0d3938c9..5dfba887 100644 --- a/internal/postgres/migrate/setup_test.go +++ b/internal/postgres/migrate/setup_test.go @@ -129,6 +129,14 @@ func TestMigrator_Setup(t *testing.T) { } func TestConfigureTarget_instance_type(t *testing.T) { + scheme, err := liberatorscheme.All() + if err != nil { + t.Fatalf("failed to create scheme: %v", err) + } + clientBuilder := ctrl_fake.NewClientBuilder().WithScheme(scheme) + clientset := fake.NewClientset() + client := clientBuilder.Build() + tests := map[string]struct { instance config.InstanceConfig }{ @@ -161,16 +169,7 @@ func TestConfigureTarget_instance_type(t *testing.T) { Namespace: namespace, Source: tc.instance, } - scheme, err := liberatorscheme.All() - if err != nil { - t.Fatalf("failed to create scheme: %v", err) - } - clientBuilder := ctrl_fake.NewClientBuilder().WithScheme(scheme) - clientset := fake.NewClientset() - migratorBuilder := func() *migrate.Migrator { - client := clientBuilder.Build() - return migrate.NewMigrator(client, clientset, cfg, true, true) - } + migratorBuilder := migrate.NewMigrator(client, clientset, cfg, true, true) ui.AskForDiskAutoresize = func(sourceDiskAutoresize option.Option[bool]) func() option.Option[bool] { return func() option.Option[bool] { @@ -195,7 +194,7 @@ func TestConfigureTarget_instance_type(t *testing.T) { t.Run("instance type target type is set", func(t *testing.T) { cfg.Target = config.InstanceConfig{InstanceName: option.Some(targetName), Type: option.Some(targetType)} - m := migratorBuilder() + m := migratorBuilder m.ConfigureTarget() if cfg.Target.Type.String() != targetType { t.Errorf("expected target type %q, got %q", targetType, cfg.Target.Type.String()) @@ -204,7 +203,7 @@ func TestConfigureTarget_instance_type(t *testing.T) { t.Run("instance type target type is not set", func(t *testing.T) { cfg.Target = config.InstanceConfig{InstanceName: option.Some(targetName)} - m := migratorBuilder() + m := migratorBuilder m.ConfigureTarget() if cfg.Target.Type != option.None[string]() { t.Errorf("expected target type to be None, got %q", cfg.Target.Type.String()) @@ -213,7 +212,7 @@ func TestConfigureTarget_instance_type(t *testing.T) { t.Run("instance tier target tier is set", func(t *testing.T) { cfg.Target = config.InstanceConfig{InstanceName: option.Some(targetName), Tier: option.Some(targetTier)} - m := migratorBuilder() + m := migratorBuilder m.ConfigureTarget() if cfg.Target.Tier.String() != targetTier { t.Errorf("expected target tier %q, got %q", targetTier, cfg.Target.Tier.String()) @@ -221,7 +220,7 @@ func TestConfigureTarget_instance_type(t *testing.T) { }) t.Run("instance tier target tier is not set", func(t *testing.T) { cfg.Target = config.InstanceConfig{InstanceName: option.Some(targetName)} - m := migratorBuilder() + m := migratorBuilder m.ConfigureTarget() if cfg.Target.Tier != option.None[string]() { t.Errorf("expected target tier to be None, got %q", cfg.Target.Tier.String()) @@ -229,7 +228,7 @@ func TestConfigureTarget_instance_type(t *testing.T) { }) t.Run("instance disk size target disk size is set", func(t *testing.T) { cfg.Target = config.InstanceConfig{InstanceName: option.Some(targetName), DiskSize: option.Some(targetDiskSize)} - m := migratorBuilder() + m := migratorBuilder m.ConfigureTarget() if cfg.Target.DiskSize.String() != fmt.Sprintf("%v", targetDiskSize) { t.Errorf("expected target disk size %d, got %s", targetDiskSize, cfg.Target.DiskSize.String()) @@ -237,7 +236,7 @@ func TestConfigureTarget_instance_type(t *testing.T) { }) t.Run("instance disk size target disk size is not set", func(t *testing.T) { cfg.Target = config.InstanceConfig{InstanceName: option.Some(targetName)} - m := migratorBuilder() + m := migratorBuilder m.ConfigureTarget() if cfg.Target.DiskSize != option.None[int]() { t.Errorf("expected target disk size to be None, got %s", cfg.Target.DiskSize.String()) @@ -249,7 +248,7 @@ func TestConfigureTarget_instance_type(t *testing.T) { DiskAutoresize: option.Some(false), DiskSize: option.Some(targetDiskSize), } - m := migratorBuilder() + m := migratorBuilder m.ConfigureTarget() if cfg.Target.DiskAutoresize.String() != "false" { t.Errorf("expected target disk autoresize to be false, got %s", cfg.Target.DiskAutoresize.String()) @@ -263,7 +262,7 @@ func TestConfigureTarget_instance_type(t *testing.T) { InstanceName: option.Some(targetName), DiskAutoresize: option.Some(false), } - m := migratorBuilder() + m := migratorBuilder m.ConfigureTarget() if cfg.Target.DiskAutoresize.String() != "false" { t.Errorf("expected target disk autoresize to be false, got %s", cfg.Target.DiskAutoresize.String()) @@ -278,7 +277,7 @@ func TestConfigureTarget_instance_type(t *testing.T) { DiskAutoresize: option.Some(true), DiskSize: option.Some(targetDiskSize), } - m := migratorBuilder() + m := migratorBuilder m.ConfigureTarget() if cfg.Target.DiskAutoresize.String() != "true" { t.Errorf("expected target disk autoresize to be true, got %s", cfg.Target.DiskAutoresize.String()) @@ -289,7 +288,7 @@ func TestConfigureTarget_instance_type(t *testing.T) { InstanceName: option.Some(targetName), DiskAutoresize: option.Some(true), } - m := migratorBuilder() + m := migratorBuilder m.ConfigureTarget() if cfg.Target.DiskAutoresize.String() != "true" { t.Errorf("expected target disk autoresize to be true, got %s", cfg.Target.DiskAutoresize.String()) @@ -297,7 +296,7 @@ func TestConfigureTarget_instance_type(t *testing.T) { }) t.Run("instance disk autoresize target disk autoresize is not set and target disk size is set", func(t *testing.T) { cfg.Target = config.InstanceConfig{InstanceName: option.Some(targetName), DiskSize: option.Some(targetDiskSize)} - m := migratorBuilder() + m := migratorBuilder m.ConfigureTarget() if cfg.Target.DiskAutoresize != option.None[bool]() { t.Errorf("expected target disk autoresize to be None, got %s", cfg.Target.DiskAutoresize.String()) @@ -308,7 +307,7 @@ func TestConfigureTarget_instance_type(t *testing.T) { }) t.Run("instance disk autoresize target disk autoresize is not set and target disk size is not set", func(t *testing.T) { cfg.Target = config.InstanceConfig{InstanceName: option.Some(targetName)} - m := migratorBuilder() + m := migratorBuilder m.ConfigureTarget() if cfg.Target.DiskAutoresize != option.None[bool]() { t.Errorf("expected target disk autoresize to be None, got %s", cfg.Target.DiskAutoresize.String()) From 97dd2054caf609f1c30f7de55fff7dd87f339512 Mon Sep 17 00:00:00 2001 From: Youssef Bel Mekki <38552193+ybelMekk@users.noreply.github.com> Date: Thu, 29 Jan 2026 09:25:44 +0100 Subject: [PATCH 4/5] chore: update Go version to 1.25.6 --- go.mod | 2 +- internal/aiven/aiven_services/stream.go | 28 ------------------------- 2 files changed, 1 insertion(+), 29 deletions(-) delete mode 100644 internal/aiven/aiven_services/stream.go diff --git a/go.mod b/go.mod index 71d1935b..34cae728 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/nais/cli -go 1.25.5 +go 1.25.6 tool ( github.com/Khan/genqlient diff --git a/internal/aiven/aiven_services/stream.go b/internal/aiven/aiven_services/stream.go deleted file mode 100644 index f49dc87a..00000000 --- a/internal/aiven/aiven_services/stream.go +++ /dev/null @@ -1,28 +0,0 @@ -package aiven_services - -import ( - kafka_nais_io_v1 "github.com/nais/liberator/pkg/apis/kafka.nais.io/v1" -) - -type Stream struct { - Pool KafkaPool - StreamPrefix string - AdditionalUsers []string -} - -func (s *Stream) Name() string { - return s.StreamPrefix -} - -func (s *Stream) Setup(setup *ServiceSetup) { - s.Pool = setup.Pool -} - -func (s *Stream) Apply(streamSpec *kafka_nais_io_v1.StreamSpec, _ string) { - streamSpec.Pool = s.Pool.String() - // streamSpec.AdditionalUsers = append(streamSpec.AdditionalUsers, TODO) -} - -func (s *Stream) Is(other Service) bool { - return s.Name() == other.Name() -} From 795736fef37d090e64530eaee392aaee9c545d53 Mon Sep 17 00:00:00 2001 From: "@x10an14-nav" Date: Thu, 29 Jan 2026 09:57:12 +0100 Subject: [PATCH 5/5] fix(grant_access): correctly pass arguments to new commands Also: - refactor some business code for simplicity/separation of concerns. - fix mise Co-authored-by: @sindrerh2 Co-authored-by: @ybelmekk --- flake.nix | 4 +- internal/aiven/command/flag/flag.go | 11 ++- internal/aiven/command/grant_access_stream.go | 14 +++- internal/aiven/command/grant_access_topic.go | 31 +++++--- internal/aiven/grant_access.go | 75 +++++++------------ mise/config.toml | 2 +- 6 files changed, 70 insertions(+), 67 deletions(-) diff --git a/flake.nix b/flake.nix index 4bf175e5..721804a0 100644 --- a/flake.nix +++ b/flake.nix @@ -6,12 +6,12 @@ outputs = { nixpkgs, ... }: let goOverlay = final: prev: let - version = "1.25.5"; + version = "1.25.6"; newerGoVersion = prev.go.overrideAttrs (old: { inherit version; src = prev.fetchurl { url = "https://go.dev/dl/go${version}.src.tar.gz"; - hash = ""; # TODO: if `version` is changed in the future + hash = "sha256-WMv3ceRNdt5vVtGeM7d9dFoeSJNAkih15GWFuXXCsFk="; }; }); nixpkgsVersion = prev.go.version; diff --git a/internal/aiven/command/flag/flag.go b/internal/aiven/command/flag/flag.go index 1bb1b702..5cbba11e 100644 --- a/internal/aiven/command/flag/flag.go +++ b/internal/aiven/command/flag/flag.go @@ -24,10 +24,15 @@ type CreateOpenSearch struct { type GrantAccess struct { *Aiven - Access string `name:"access" short:"x" usage:"Access |LEVEL| (readwrite, read and write)."` } -type GrantAccessCommon struct { +type GrantAccessStream struct { *GrantAccess - Namespace string `name:"namespace" short:"n" usage:"|NAMESPACE| of the Stream.kafka.nais.io's |NAMESPACE|."` + Namespace string `name:"namespace" short:"n" usage:"|NAMESPACE| of the stream.kafka.nais.io resource."` +} + +type GrantAccessTopic struct { + *GrantAccess + Access string `name:"access" short:"x" usage:"Access |LEVEL| (readwrite, read and write)."` + Namespace string `name:"namespace" short:"n" usage:"|NAMESPACE| of the topic.kafka.nais.io resource."` } diff --git a/internal/aiven/command/grant_access_stream.go b/internal/aiven/command/grant_access_stream.go index dc434627..6fd9850e 100644 --- a/internal/aiven/command/grant_access_stream.go +++ b/internal/aiven/command/grant_access_stream.go @@ -2,6 +2,7 @@ package command import ( "context" + "fmt" "github.com/nais/cli/internal/aiven" "github.com/nais/cli/internal/aiven/command/flag" @@ -9,7 +10,7 @@ import ( ) func grantAccessStream(parentFlags *flag.GrantAccess) *naistrix.Command { - grantAccessStreamFlags := &flag.GrantAccessCommon{GrantAccess: parentFlags} + grantAccessStreamFlags := &flag.GrantAccessStream{GrantAccess: parentFlags} return &naistrix.Command{ Name: "stream", @@ -19,8 +20,15 @@ func grantAccessStream(parentFlags *flag.GrantAccess) *naistrix.Command { {Name: "username"}, {Name: "stream"}, }, + ValidateFunc: func(context.Context, *naistrix.Arguments) error { + if grantAccessStreamFlags.Namespace == "" { + return fmt.Errorf("--namespace is required\n\tPS: Check `nais config set`") + } + + return nil + }, RunFunc: func(ctx context.Context, args *naistrix.Arguments, out *naistrix.OutputWriter) error { - namespace := args.Get("namespace") + namespace := grantAccessStreamFlags.Namespace userName := args.Get("username") stream := args.Get("stream") @@ -29,7 +37,7 @@ func grantAccessStream(parentFlags *flag.GrantAccess) *naistrix.Command { return err } - if !accessResult.Added { + if accessResult.AlreadyAdded { out.Printf("Username '%s' already listed in Stream '%s/%s' ACLs.", userName, namespace, stream) return nil } diff --git a/internal/aiven/command/grant_access_topic.go b/internal/aiven/command/grant_access_topic.go index 6e4e17d6..bbcbe8e2 100644 --- a/internal/aiven/command/grant_access_topic.go +++ b/internal/aiven/command/grant_access_topic.go @@ -2,6 +2,7 @@ package command import ( "context" + "fmt" "github.com/nais/cli/internal/aiven" "github.com/nais/cli/internal/aiven/command/flag" @@ -10,7 +11,7 @@ import ( ) func grantAccessTopic(parentFlags *flag.GrantAccess) *naistrix.Command { - grantAccessTopicFlags := &flag.GrantAccessCommon{GrantAccess: parentFlags} + grantAccessTopicFlags := &flag.GrantAccessTopic{GrantAccess: parentFlags, Access: "read"} return &naistrix.Command{ Name: "topic", @@ -20,30 +21,38 @@ func grantAccessTopic(parentFlags *flag.GrantAccess) *naistrix.Command { {Name: "username"}, {Name: "topic"}, }, + ValidateFunc: func(context.Context, *naistrix.Arguments) error { + if grantAccessTopicFlags.Namespace == "" { + return fmt.Errorf("--namespace is required\n\tPS: Check `nais config set`") + } + + return nil + }, RunFunc: func(ctx context.Context, args *naistrix.Arguments, out *naistrix.OutputWriter) error { - namespace := args.Get("namespace") + access := grantAccessTopicFlags.Access + namespace := grantAccessTopicFlags.Namespace topicName := args.Get("topic") + username := args.Get("username") - acl := nais_kafka.TopicACL{ + newAcl := nais_kafka.TopicACL{ Team: namespace, - Application: args.Get("username"), - Access: args.Get("access"), + Application: username, + Access: access, } - - accessResult, err := aiven.GrantAccessToTopic(ctx, namespace, topicName, acl) + accessResult, err := aiven.GrantAccessToTopic(ctx, namespace, topicName, newAcl) if err != nil { return err } - if !accessResult.Added { - out.Printf("ACL already exists for team '%s', application '%s', access '%s' on topic '%s/%s'.", - acl.Team, acl.Application, acl.Access, namespace, topicName, + if accessResult.AlreadyAdded { + out.Printf("An ACL already exists for user/access '%s' on topic '%s/%s'.", + newAcl.Application, newAcl.Access, namespace, topicName, ) return nil } out.Printf("ACL added for team '%s', application '%s', access '%s' on topic '%s/%s'.", - acl.Team, acl.Application, acl.Access, namespace, topicName, + newAcl.Team, newAcl.Application, newAcl.Access, namespace, topicName, ) return nil }, diff --git a/internal/aiven/grant_access.go b/internal/aiven/grant_access.go index 6ac70a12..ef942f94 100644 --- a/internal/aiven/grant_access.go +++ b/internal/aiven/grant_access.go @@ -10,14 +10,12 @@ import ( ) type GrantAccessResult struct { - Added bool - Namespace string - Name string - Kind string - Detail string + AlreadyAdded bool + Namespace string + Name string } -func GrantAccessToTopic(ctx context.Context, namespace, topicName string, acl nais_kafka.TopicACL) (*GrantAccessResult, error) { +func GrantAccessToTopic(ctx context.Context, namespace, topicName string, newAcl nais_kafka.TopicACL) (*GrantAccessResult, error) { client := k8s.SetupControllerRuntimeClient() if err := validateNamespace(ctx, client, namespace); err != nil { @@ -26,37 +24,26 @@ func GrantAccessToTopic(ctx context.Context, namespace, topicName string, acl na var topic nais_kafka.Topic if err := client.Get(ctx, ctrl.ObjectKey{Name: topicName, Namespace: namespace}, &topic); err != nil { - return nil, fmt.Errorf("validate topic: %w", err) + return nil, fmt.Errorf("get topic: %w", err) } - // Default to read access if not specified - if acl.Access == "" { - acl.Access = "read" - } - - newACLs, added := ensureTopicACL(topic.Spec.ACL, acl) - if !added { + if checkIfAclInList(topic.Spec.ACL, newAcl) { return &GrantAccessResult{ - Added: false, - Namespace: namespace, - Name: topic.Name, - Kind: topic.Kind, - Detail: acl.Access, + AlreadyAdded: true, + Namespace: namespace, + Name: topicName, }, nil } - - topic.Spec.ACL = newACLs + topic.Spec.ACL = append(topic.Spec.ACL, newAcl) if err := client.Update(ctx, &topic); err != nil { return nil, fmt.Errorf("update topic: %w", err) } return &GrantAccessResult{ - Added: true, - Namespace: namespace, - Name: topic.Name, - Kind: topic.Kind, - Detail: acl.Access, + AlreadyAdded: false, + Namespace: namespace, + Name: topicName, }, nil } @@ -69,49 +56,43 @@ func GrantAccessToStream(ctx context.Context, namespace, streamName, userName st var stream nais_kafka.Stream if err := client.Get(ctx, ctrl.ObjectKey{Name: streamName, Namespace: namespace}, &stream); err != nil { - return nil, fmt.Errorf("validate stream: %w", err) + return nil, fmt.Errorf("get stream: %w", err) } - newUsers, added := ensureAdditionalStreamUser(stream.Spec.AdditionalUsers, userName) - if !added { + if checkIfUserInList(stream.Spec.AdditionalUsers, userName) { return &GrantAccessResult{ - Added: false, - Namespace: namespace, - Name: stream.Name, - Kind: stream.Kind, - Detail: userName, + AlreadyAdded: true, + Namespace: namespace, + Name: streamName, }, nil } - - stream.Spec.AdditionalUsers = newUsers + stream.Spec.AdditionalUsers = append(stream.Spec.AdditionalUsers, nais_kafka.AdditionalStreamUser{Username: userName}) if err := client.Update(ctx, &stream); err != nil { return nil, fmt.Errorf("update stream: %w", err) } return &GrantAccessResult{ - Added: true, - Namespace: namespace, - Name: stream.Name, - Kind: stream.Kind, - Detail: userName, + AlreadyAdded: false, + Namespace: namespace, + Name: streamName, }, nil } -func ensureTopicACL(existing []nais_kafka.TopicACL, wanted nais_kafka.TopicACL) ([]nais_kafka.TopicACL, bool) { +func checkIfAclInList(existing []nais_kafka.TopicACL, wanted nais_kafka.TopicACL) bool { for _, e := range existing { if e.Team == wanted.Team && e.Application == wanted.Application && e.Access == wanted.Access { - return existing, false + return true } } - return append(existing, wanted), true + return false } -func ensureAdditionalStreamUser(existing []nais_kafka.AdditionalStreamUser, userName string) ([]nais_kafka.AdditionalStreamUser, bool) { +func checkIfUserInList(existing []nais_kafka.AdditionalStreamUser, userName string) bool { for _, u := range existing { if u.Username == userName { - return existing, false + return true } } - return append(existing, nais_kafka.AdditionalStreamUser{Username: userName}), true + return false } diff --git a/mise/config.toml b/mise/config.toml index 8018932f..0cced1fb 100644 --- a/mise/config.toml +++ b/mise/config.toml @@ -1,6 +1,6 @@ [tools] git-cliff = "2.10.1" -go = "1.25.5" +go = "1.25.6" yamlfmt = "0.17.2" [settings]