From b489cece05693a8121e30f5c3cd987e3fff97edd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 30 Oct 2025 21:21:35 +0000 Subject: [PATCH 1/7] Initial plan From 9f9daf818e52d7eb9f5446b35ff0acf3fa16513c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 30 Oct 2025 21:33:55 +0000 Subject: [PATCH 2/7] Add config passing to external plugins Co-authored-by: camilamacedo86 <7708031+camilamacedo86@users.noreply.github.com> --- pkg/plugin/external/types.go | 4 + pkg/plugins/external/api.go | 10 +- pkg/plugins/external/edit.go | 10 +- pkg/plugins/external/external_test.go | 150 ++++++++++++++++++++++++++ pkg/plugins/external/helpers.go | 19 +++- pkg/plugins/external/init.go | 10 +- pkg/plugins/external/webhook.go | 10 +- 7 files changed, 208 insertions(+), 5 deletions(-) diff --git a/pkg/plugin/external/types.go b/pkg/plugin/external/types.go index 914ab054d6f..854f110baa4 100644 --- a/pkg/plugin/external/types.go +++ b/pkg/plugin/external/types.go @@ -35,6 +35,10 @@ type PluginRequest struct { // Universe represents the modified file contents that gets updated over a series of plugin runs // across the plugin chain. Initially, it starts out as empty. Universe map[string]string `json:"universe"` + + // Config contains the PROJECT file config. This field may be empty if the + // project is being initialized and the PROJECT file has not been created yet. + Config map[string]interface{} `json:"config,omitempty"` } // PluginResponse is returned to kubebuilder by the plugin and contains all files diff --git a/pkg/plugins/external/api.go b/pkg/plugins/external/api.go index 4a06c8044eb..c140ea78b6a 100644 --- a/pkg/plugins/external/api.go +++ b/pkg/plugins/external/api.go @@ -19,6 +19,7 @@ package external import ( "github.com/spf13/pflag" + "sigs.k8s.io/kubebuilder/v4/pkg/config" "sigs.k8s.io/kubebuilder/v4/pkg/machinery" "sigs.k8s.io/kubebuilder/v4/pkg/model/resource" "sigs.k8s.io/kubebuilder/v4/pkg/plugin" @@ -32,6 +33,8 @@ const ( ) type createAPISubcommand struct { + config config.Config + Path string Args []string } @@ -49,6 +52,11 @@ func (p *createAPISubcommand) BindFlags(fs *pflag.FlagSet) { bindExternalPluginFlags(fs, "api", p.Path, p.Args) } +func (p *createAPISubcommand) InjectConfig(c config.Config) error { + p.config = c + return nil +} + func (p *createAPISubcommand) Scaffold(fs machinery.Filesystem) error { req := external.PluginRequest{ APIVersion: defaultAPIVersion, @@ -56,7 +64,7 @@ func (p *createAPISubcommand) Scaffold(fs machinery.Filesystem) error { Args: p.Args, } - err := handlePluginResponse(fs, req, p.Path) + err := handlePluginResponse(fs, req, p.Path, p.config) if err != nil { return err } diff --git a/pkg/plugins/external/edit.go b/pkg/plugins/external/edit.go index 0cb7a9ee5be..110049276cc 100644 --- a/pkg/plugins/external/edit.go +++ b/pkg/plugins/external/edit.go @@ -19,6 +19,7 @@ package external import ( "github.com/spf13/pflag" + "sigs.k8s.io/kubebuilder/v4/pkg/config" "sigs.k8s.io/kubebuilder/v4/pkg/machinery" "sigs.k8s.io/kubebuilder/v4/pkg/plugin" "sigs.k8s.io/kubebuilder/v4/pkg/plugin/external" @@ -27,6 +28,8 @@ import ( var _ plugin.EditSubcommand = &editSubcommand{} type editSubcommand struct { + config config.Config + Path string Args []string } @@ -39,6 +42,11 @@ func (p *editSubcommand) BindFlags(fs *pflag.FlagSet) { bindExternalPluginFlags(fs, "edit", p.Path, p.Args) } +func (p *editSubcommand) InjectConfig(c config.Config) error { + p.config = c + return nil +} + func (p *editSubcommand) Scaffold(fs machinery.Filesystem) error { req := external.PluginRequest{ APIVersion: defaultAPIVersion, @@ -46,7 +54,7 @@ func (p *editSubcommand) Scaffold(fs machinery.Filesystem) error { Args: p.Args, } - err := handlePluginResponse(fs, req, p.Path) + err := handlePluginResponse(fs, req, p.Path, p.config) if err != nil { return err } diff --git a/pkg/plugins/external/external_test.go b/pkg/plugins/external/external_test.go index 2b8e0cbdb47..c907c32ebfd 100644 --- a/pkg/plugins/external/external_test.go +++ b/pkg/plugins/external/external_test.go @@ -28,6 +28,7 @@ import ( "github.com/spf13/afero" "github.com/spf13/pflag" + "sigs.k8s.io/kubebuilder/v4/pkg/config/v3" "sigs.k8s.io/kubebuilder/v4/pkg/machinery" "sigs.k8s.io/kubebuilder/v4/pkg/plugin" "sigs.k8s.io/kubebuilder/v4/pkg/plugin/external" @@ -75,6 +76,28 @@ func (m *mockInValidOsWdGetter) GetCurrentDir() (string, error) { return "", fmt.Errorf("error getting current directory") } +// mockConfigOutputGetter captures the request to verify config is passed +type mockConfigOutputGetter struct { + capturedRequest *external.PluginRequest +} + +var _ ExecOutputGetter = &mockConfigOutputGetter{} + +func (m *mockConfigOutputGetter) GetExecOutput(reqBytes []byte, _ string) ([]byte, error) { + // Capture the request for verification + m.capturedRequest = &external.PluginRequest{} + if err := json.Unmarshal(reqBytes, m.capturedRequest); err != nil { + return nil, fmt.Errorf("error unmarshalling request: %w", err) + } + + return []byte(`{ + "command": "init", + "error": false, + "error_msg": "none", + "universe": {"LICENSE": "Apache 2.0 License\n"} + }`), nil +} + type mockValidFlagOutputGetter struct{} func (m *mockValidFlagOutputGetter) GetExecOutput(_ []byte, _ string) ([]byte, error) { @@ -754,6 +777,133 @@ var _ = Describe("Run external plugin using Scaffold", func() { } }) }) + + Context("with config injection", func() { + const filePerm os.FileMode = 755 + var ( + pluginFileName string + args []string + f afero.File + fs machinery.Filesystem + mockGetter *mockConfigOutputGetter + cfg *v3.Cfg + + err error + ) + + BeforeEach(func() { + mockGetter = &mockConfigOutputGetter{} + outputGetter = mockGetter + currentDirGetter = &mockValidOsWdGetter{} + fs = machinery.Filesystem{ + FS: afero.NewMemMapFs(), + } + + pluginFileName = "externalPlugin.sh" + pluginFilePath := filepath.Join("tmp", "externalPlugin", pluginFileName) + + err = fs.FS.MkdirAll(filepath.Dir(pluginFilePath), filePerm) + Expect(err).ToNot(HaveOccurred()) + + f, err = fs.FS.Create(pluginFilePath) + Expect(err).ToNot(HaveOccurred()) + Expect(f).ToNot(BeNil()) + + _, err = fs.FS.Stat(pluginFilePath) + Expect(err).ToNot(HaveOccurred()) + + args = []string{"--domain", "example.com"} + + // Create a config instance + cfg = &v3.Cfg{ + Version: v3.Version, + Domain: "test.domain", + Repository: "github.com/test/repo", + Name: "test-project", + } + }) + + It("should pass config to external plugin on init subcommand", func() { + i := initSubcommand{ + Path: pluginFileName, + Args: args, + config: cfg, + } + + err = i.Scaffold(fs) + Expect(err).ToNot(HaveOccurred()) + + // Verify that config was captured in the request + Expect(mockGetter.capturedRequest).ToNot(BeNil()) + Expect(mockGetter.capturedRequest.Config).ToNot(BeNil()) + Expect(mockGetter.capturedRequest.Config["domain"]).To(Equal("test.domain")) + Expect(mockGetter.capturedRequest.Config["repo"]).To(Equal("github.com/test/repo")) + Expect(mockGetter.capturedRequest.Config["projectName"]).To(Equal("test-project")) + }) + + It("should pass config to external plugin on create api subcommand", func() { + c := createAPISubcommand{ + Path: pluginFileName, + Args: args, + config: cfg, + } + + err = c.Scaffold(fs) + Expect(err).ToNot(HaveOccurred()) + + // Verify that config was captured in the request + Expect(mockGetter.capturedRequest).ToNot(BeNil()) + Expect(mockGetter.capturedRequest.Config).ToNot(BeNil()) + Expect(mockGetter.capturedRequest.Config["domain"]).To(Equal("test.domain")) + }) + + It("should pass config to external plugin on create webhook subcommand", func() { + c := createWebhookSubcommand{ + Path: pluginFileName, + Args: args, + config: cfg, + } + + err = c.Scaffold(fs) + Expect(err).ToNot(HaveOccurred()) + + // Verify that config was captured in the request + Expect(mockGetter.capturedRequest).ToNot(BeNil()) + Expect(mockGetter.capturedRequest.Config).ToNot(BeNil()) + Expect(mockGetter.capturedRequest.Config["domain"]).To(Equal("test.domain")) + }) + + It("should pass config to external plugin on edit subcommand", func() { + e := editSubcommand{ + Path: pluginFileName, + Args: args, + config: cfg, + } + + err = e.Scaffold(fs) + Expect(err).ToNot(HaveOccurred()) + + // Verify that config was captured in the request + Expect(mockGetter.capturedRequest).ToNot(BeNil()) + Expect(mockGetter.capturedRequest.Config).ToNot(BeNil()) + Expect(mockGetter.capturedRequest.Config["domain"]).To(Equal("test.domain")) + }) + + It("should handle nil config gracefully", func() { + i := initSubcommand{ + Path: pluginFileName, + Args: args, + config: nil, + } + + err = i.Scaffold(fs) + Expect(err).ToNot(HaveOccurred()) + + // Verify that request was made but config is nil + Expect(mockGetter.capturedRequest).ToNot(BeNil()) + Expect(mockGetter.capturedRequest.Config).To(BeNil()) + }) + }) }) func getFlags() []external.Flag { diff --git a/pkg/plugins/external/helpers.go b/pkg/plugins/external/helpers.go index 7f59541a75a..c9f950c8e14 100644 --- a/pkg/plugins/external/helpers.go +++ b/pkg/plugins/external/helpers.go @@ -30,7 +30,9 @@ import ( "github.com/spf13/afero" "github.com/spf13/pflag" + "sigs.k8s.io/yaml" + "sigs.k8s.io/kubebuilder/v4/pkg/config" "sigs.k8s.io/kubebuilder/v4/pkg/machinery" "sigs.k8s.io/kubebuilder/v4/pkg/plugin" "sigs.k8s.io/kubebuilder/v4/pkg/plugin/external" @@ -149,7 +151,7 @@ func getUniverseMap(fs machinery.Filesystem) (map[string]string, error) { return universe, nil } -func handlePluginResponse(fs machinery.Filesystem, req external.PluginRequest, path string) error { +func handlePluginResponse(fs machinery.Filesystem, req external.PluginRequest, path string, cfg config.Config) error { var err error req.Universe, err = getUniverseMap(fs) @@ -157,6 +159,21 @@ func handlePluginResponse(fs machinery.Filesystem, req external.PluginRequest, p return fmt.Errorf("error getting universe map: %w", err) } + // Marshal config to include in the request if config is provided + if cfg != nil { + configData, err := cfg.MarshalYAML() + if err != nil { + return fmt.Errorf("error marshaling config: %w", err) + } + + var configMap map[string]interface{} + if err = yaml.Unmarshal(configData, &configMap); err != nil { + return fmt.Errorf("error unmarshaling config to map: %w", err) + } + + req.Config = configMap + } + res, err := makePluginRequest(req, path) if err != nil { return fmt.Errorf("error making request to external plugin: %w", err) diff --git a/pkg/plugins/external/init.go b/pkg/plugins/external/init.go index 176b9b044e6..36ddacad268 100644 --- a/pkg/plugins/external/init.go +++ b/pkg/plugins/external/init.go @@ -19,6 +19,7 @@ package external import ( "github.com/spf13/pflag" + "sigs.k8s.io/kubebuilder/v4/pkg/config" "sigs.k8s.io/kubebuilder/v4/pkg/machinery" "sigs.k8s.io/kubebuilder/v4/pkg/plugin" "sigs.k8s.io/kubebuilder/v4/pkg/plugin/external" @@ -27,6 +28,8 @@ import ( var _ plugin.InitSubcommand = &initSubcommand{} type initSubcommand struct { + config config.Config + Path string Args []string } @@ -39,6 +42,11 @@ func (p *initSubcommand) BindFlags(fs *pflag.FlagSet) { bindExternalPluginFlags(fs, "init", p.Path, p.Args) } +func (p *initSubcommand) InjectConfig(c config.Config) error { + p.config = c + return nil +} + func (p *initSubcommand) Scaffold(fs machinery.Filesystem) error { req := external.PluginRequest{ APIVersion: defaultAPIVersion, @@ -46,7 +54,7 @@ func (p *initSubcommand) Scaffold(fs machinery.Filesystem) error { Args: p.Args, } - err := handlePluginResponse(fs, req, p.Path) + err := handlePluginResponse(fs, req, p.Path, p.config) if err != nil { return err } diff --git a/pkg/plugins/external/webhook.go b/pkg/plugins/external/webhook.go index 259d42822ee..5e1d96bcd8d 100644 --- a/pkg/plugins/external/webhook.go +++ b/pkg/plugins/external/webhook.go @@ -19,6 +19,7 @@ package external import ( "github.com/spf13/pflag" + "sigs.k8s.io/kubebuilder/v4/pkg/config" "sigs.k8s.io/kubebuilder/v4/pkg/machinery" "sigs.k8s.io/kubebuilder/v4/pkg/model/resource" "sigs.k8s.io/kubebuilder/v4/pkg/plugin" @@ -28,6 +29,8 @@ import ( var _ plugin.CreateWebhookSubcommand = &createWebhookSubcommand{} type createWebhookSubcommand struct { + config config.Config + Path string Args []string } @@ -45,6 +48,11 @@ func (p *createWebhookSubcommand) BindFlags(fs *pflag.FlagSet) { bindExternalPluginFlags(fs, "webhook", p.Path, p.Args) } +func (p *createWebhookSubcommand) InjectConfig(c config.Config) error { + p.config = c + return nil +} + func (p *createWebhookSubcommand) Scaffold(fs machinery.Filesystem) error { req := external.PluginRequest{ APIVersion: defaultAPIVersion, @@ -52,7 +60,7 @@ func (p *createWebhookSubcommand) Scaffold(fs machinery.Filesystem) error { Args: p.Args, } - err := handlePluginResponse(fs, req, p.Path) + err := handlePluginResponse(fs, req, p.Path, p.config) if err != nil { return err } From 4e612eed1cb31d8bc26d73efde88f4da492cdd6c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 30 Oct 2025 21:35:16 +0000 Subject: [PATCH 3/7] Update external plugin documentation with config field Co-authored-by: camilamacedo86 <7708031+camilamacedo86@users.noreply.github.com> --- .../src/plugins/extending/external-plugins.md | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/docs/book/src/plugins/extending/external-plugins.md b/docs/book/src/plugins/extending/external-plugins.md index a957f88fcc8..51bdf0dac73 100644 --- a/docs/book/src/plugins/extending/external-plugins.md +++ b/docs/book/src/plugins/extending/external-plugins.md @@ -41,6 +41,28 @@ structures. } ``` +**Note:** When executing commands other than `init` (e.g., `create api`, `create webhook`, `edit`), the `PluginRequest` will also include a `config` field containing the PROJECT file configuration: + +```json +{ + "apiVersion": "v1alpha1", + "args": ["--group", "crew", "--version", "v1", "--kind", "Captain"], + "command": "create api", + "universe": {}, + "config": { + "domain": "my.domain", + "repo": "github.com/example/my-project", + "projectName": "my-project", + "version": "3", + "layout": ["go.kubebuilder.io/v4"], + "multigroup": false, + "resources": [] + } +} +``` + +The `config` field provides external plugins access to the PROJECT file configuration, enabling them to make informed decisions based on the project's settings. This field may be empty during the `init` command if the PROJECT file has not been created yet. + ### PluginResponse `PluginResponse` contains the modifications made by the plugin to the project. This data is serialized as JSON and returned to Kubebuilder through `stdout`. From 7871066b0f28c36f1f379ec4f18d65bfc3107fb8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 30 Oct 2025 21:36:53 +0000 Subject: [PATCH 4/7] Clarify config field omission in external plugin docs Co-authored-by: camilamacedo86 <7708031+camilamacedo86@users.noreply.github.com> --- docs/book/src/plugins/extending/external-plugins.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/book/src/plugins/extending/external-plugins.md b/docs/book/src/plugins/extending/external-plugins.md index 51bdf0dac73..6d06f28a1d9 100644 --- a/docs/book/src/plugins/extending/external-plugins.md +++ b/docs/book/src/plugins/extending/external-plugins.md @@ -61,7 +61,7 @@ structures. } ``` -The `config` field provides external plugins access to the PROJECT file configuration, enabling them to make informed decisions based on the project's settings. This field may be empty during the `init` command if the PROJECT file has not been created yet. +The `config` field provides external plugins access to the PROJECT file configuration, enabling them to make informed decisions based on the project's settings. This field will be omitted from the JSON entirely (not present) during the `init` command if the PROJECT file has not been created yet. External plugins should check for the presence of this field before attempting to use it. ### PluginResponse From 0f5974244d57ccc739c9cf61aad3a72ff69a9156 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 30 Oct 2025 21:41:11 +0000 Subject: [PATCH 5/7] Feature complete: Make config accessible for external plugins Co-authored-by: camilamacedo86 <7708031+camilamacedo86@users.noreply.github.com> --- docs/book/src/multiversion-tutorial/testdata/project/go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/book/src/multiversion-tutorial/testdata/project/go.mod b/docs/book/src/multiversion-tutorial/testdata/project/go.mod index 2c5462cb4cd..4519ca4049c 100644 --- a/docs/book/src/multiversion-tutorial/testdata/project/go.mod +++ b/docs/book/src/multiversion-tutorial/testdata/project/go.mod @@ -9,6 +9,7 @@ require ( k8s.io/api v0.34.1 k8s.io/apimachinery v0.34.1 k8s.io/client-go v0.34.1 + k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 sigs.k8s.io/controller-runtime v0.22.3 ) @@ -92,7 +93,6 @@ require ( k8s.io/component-base v0.34.1 // indirect k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b // indirect - k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect sigs.k8s.io/randfill v1.0.0 // indirect From 62ce014f6b66bbaf39bd6574b134bbaedb3c819b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 30 Oct 2025 22:33:21 +0000 Subject: [PATCH 6/7] Fix lint issues: shadow declaration, goimports, and code duplication Co-authored-by: camilamacedo86 <7708031+camilamacedo86@users.noreply.github.com> --- pkg/plugins/external/edit.go | 2 ++ pkg/plugins/external/external_test.go | 2 +- pkg/plugins/external/helpers.go | 3 ++- pkg/plugins/external/init.go | 2 ++ 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/pkg/plugins/external/edit.go b/pkg/plugins/external/edit.go index 110049276cc..5db108207d9 100644 --- a/pkg/plugins/external/edit.go +++ b/pkg/plugins/external/edit.go @@ -42,11 +42,13 @@ func (p *editSubcommand) BindFlags(fs *pflag.FlagSet) { bindExternalPluginFlags(fs, "edit", p.Path, p.Args) } +//nolint:dupl func (p *editSubcommand) InjectConfig(c config.Config) error { p.config = c return nil } +//nolint:dupl func (p *editSubcommand) Scaffold(fs machinery.Filesystem) error { req := external.PluginRequest{ APIVersion: defaultAPIVersion, diff --git a/pkg/plugins/external/external_test.go b/pkg/plugins/external/external_test.go index c907c32ebfd..21cd0ae070a 100644 --- a/pkg/plugins/external/external_test.go +++ b/pkg/plugins/external/external_test.go @@ -28,7 +28,7 @@ import ( "github.com/spf13/afero" "github.com/spf13/pflag" - "sigs.k8s.io/kubebuilder/v4/pkg/config/v3" + v3 "sigs.k8s.io/kubebuilder/v4/pkg/config/v3" "sigs.k8s.io/kubebuilder/v4/pkg/machinery" "sigs.k8s.io/kubebuilder/v4/pkg/plugin" "sigs.k8s.io/kubebuilder/v4/pkg/plugin/external" diff --git a/pkg/plugins/external/helpers.go b/pkg/plugins/external/helpers.go index c9f950c8e14..d6fad7c3792 100644 --- a/pkg/plugins/external/helpers.go +++ b/pkg/plugins/external/helpers.go @@ -161,7 +161,8 @@ func handlePluginResponse(fs machinery.Filesystem, req external.PluginRequest, p // Marshal config to include in the request if config is provided if cfg != nil { - configData, err := cfg.MarshalYAML() + var configData []byte + configData, err = cfg.MarshalYAML() if err != nil { return fmt.Errorf("error marshaling config: %w", err) } diff --git a/pkg/plugins/external/init.go b/pkg/plugins/external/init.go index 36ddacad268..4885d5380b6 100644 --- a/pkg/plugins/external/init.go +++ b/pkg/plugins/external/init.go @@ -42,11 +42,13 @@ func (p *initSubcommand) BindFlags(fs *pflag.FlagSet) { bindExternalPluginFlags(fs, "init", p.Path, p.Args) } +//nolint:dupl func (p *initSubcommand) InjectConfig(c config.Config) error { p.config = c return nil } +//nolint:dupl func (p *initSubcommand) Scaffold(fs machinery.Filesystem) error { req := external.PluginRequest{ APIVersion: defaultAPIVersion, From 4fee92f144135003e1df20153c9bd140f4cfca40 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 31 Oct 2025 17:41:20 +0000 Subject: [PATCH 7/7] Run make install and make generate to update scaffolds Co-authored-by: camilamacedo86 <7708031+camilamacedo86@users.noreply.github.com> --- docs/book/src/multiversion-tutorial/testdata/project/go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/book/src/multiversion-tutorial/testdata/project/go.mod b/docs/book/src/multiversion-tutorial/testdata/project/go.mod index 4519ca4049c..2c5462cb4cd 100644 --- a/docs/book/src/multiversion-tutorial/testdata/project/go.mod +++ b/docs/book/src/multiversion-tutorial/testdata/project/go.mod @@ -9,7 +9,6 @@ require ( k8s.io/api v0.34.1 k8s.io/apimachinery v0.34.1 k8s.io/client-go v0.34.1 - k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 sigs.k8s.io/controller-runtime v0.22.3 ) @@ -93,6 +92,7 @@ require ( k8s.io/component-base v0.34.1 // indirect k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b // indirect + k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect sigs.k8s.io/randfill v1.0.0 // indirect