🐛 (go/v4): return an error when --controller-name is invalid instead of failing silently - #5926
Conversation
updateControllers in pkg/plugins/golang/options.go discarded both calls to Controllers.AddController with `_ =`. AddController validates the name as a DNS-1035 label and rejects duplicates, but the error was never propagated. validateController in pkg/plugins/golang/v4/api.go only checks emptiness/duplicates against the resource already persisted in the PROJECT file, and never runs for a brand-new resource (GetResource returns an error, so validateController returns nil immediately). So for a new API, an invalid --controller-name (for example "Backup_Ctrl", which fails DNS-1035 validation) was silently discarded by AddController, res.Controllers stayed empty, and the scaffolding logic in api.go fell back to the default kind-derived controller name while the CLI reported success. Changes updateControllers and UpdateResource to return error and propagates it through the three call sites in v4/api.go, v4/webhook.go and deploy-image/v1alpha1/api.go, matching the existing "error updating resource: %w" wrapping convention already used alongside these call sites. Adds a new ControllerName validation test block in options_test.go covering a valid name, an invalid name (asserts the error is returned and Controllers stays empty instead of silently falling back), and a duplicate name. Also updates the five pre-existing bare options.UpdateResource(...) calls in the same test file to assert Succeed(), since they now discard the same class of error the production code used to.
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: onkar717 The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
Welcome @onkar717! |
|
Hi @onkar717. Thanks for your PR. I'm waiting for a kubernetes-sigs member to verify that this patch is reasonable to test. If it is, they should reply with Regular contributors should join the org to skip this step. Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
PROJECT file cannot be updated with the requested configuration.
PROJECT file cannot be updated with the requested configuration.PROJECT file cannot be updated with the requested configuration.
PROJECT file cannot be updated with the requested configuration.There was a problem hiding this comment.
Hi @onkar717,
Thank you so much for looking into this.
I reviewed the changes, and I think we need to address a few points before merging. Could you please take another look?
I centralized my findings below and used AI to help organize the wording.
1. validateController still skips new resources
In pkg/plugins/golang/v4/api.go, the early return mentioned in the PR description is still unchanged:
existingRes, err := p.config.GetResource(p.resource.GVK)
if err != nil {
return nil // New resources are not validated.
}Because --controller-name is a flag value, it should be validated before this return:
if p.options.ControllerName != "" {
if err := (resource.Controller{Name: p.options.ControllerName}).Validate(); err != nil {
return fmt.Errorf("invalid '--controller-name': %w", err)
}
}2. InjectResource validates after mutating the configuration
In the same file, UpdateResource runs before validateController, so the deeper AddController error is always returned first.
The validation should happen before the configuration is mutated:
if err := p.validateController(); err != nil {
return err
}
if err := p.options.UpdateResource(p.resource, p.config); err != nil {
return fmt.Errorf("error updating resource: %w", err)
}validateAPI() can remain as the final call. validateController only reads the flags, GVK, and configuration, so this reordering should be safe.
Items 1 and 2 need to be addressed together. Applying only one of them would not change the current behavior.
3. Simplify the error message
The current error is:
error updating resource: error adding controller "Backup_Ctrl": invalid controller name "Backup_Ctrl": ...
The controller name appears twice. Controller.Validate() already returns a complete error, so the wrapper only needs to identify the flag.
4. One discarded error remains
In pkg/model/resource/resource.go:283, the following error is still ignored:
_ = r.Controllers.AddController(defaultName)This follows the same legacy migration path. Since Resource.Update already returns an error, this should be a straightforward one-line fix.
This path is used when merging existing PROJECT file configurations.
5. Two call sites cannot currently trigger this error
webhook.go never sets DoController, and deploy-image/api.go never sets ControllerName.
At the moment, only create api --controller-name can trigger this validation error. Keeping the error propagation in the other call sites is fine, but the PR description should clarify this.
6. Add tests one layer higher
The new tests call Options.UpdateResource directly. Please also add:
- A CLI-level test confirming that
create api --controller-name=Bad_Nameis rejected. - A test covering the legacy migration path in
resource.go.
| } | ||
|
|
||
| if err := p.resource.Validate(); err != nil { | ||
| return fmt.Errorf("error validating resource: %w", err) |
There was a problem hiding this comment.
The description says validateController "only checked existing resources,
skipping validation for new ones", but the function is never changed here — the
api.go diff is only the wrap around UpdateResource. This early return is
what skips new resources, and it is still there:
existingRes, err := p.config.GetResource(p.resource.GVK)
if err != nil {
// Resource does not exist yet, no validation needed
return nil
}
The PR routes around it by surfacing the error from AddController deep in the
data layer. Both changes are worth having, but the flag itself should be checked
where the other flags are checked:
// The name must be valid even when the resource is new and has nothing to compare against.
if p.options.ControllerName != "" {
if err := (resource.Controller{Name: p.options.ControllerName}).Validate(); err != nil {
return fmt.Errorf("invalid '--controller-name': %w", err)
}
}| @@ -146,7 +146,9 @@ func (p *createAPISubcommand) InjectResource(res *resource.Resource) error { | |||
| p.options.DoController = true | |||
There was a problem hiding this comment.
I think that 2/3 call can never produce an error. webhook.go never sets DoController, so updateControllers sn't called at all. deploy-image/api.go sets DoController = true but never sets ControllerName, so it hits the early return nil. Only create api --controller-name=... can actually fail. Keeping the plumbing is fine, but the PR description should say so — otherwise a reviewer assumes webhook behavior changed.
Could you please check it out?
| @@ -165,7 +165,9 @@ func (p *createWebhookSubcommand) InjectResource(res *resource.Resource) error { | |||
| return errors.New("'--external-api-module' requires '--external-api-path' to be specified") | |||
| } | |||
There was a problem hiding this comment.
I think that to solve what you want to solve unless I misunderstood it we would need to:
Current:
existingRes, err := p.config.GetResource(p.resource.GVK)
if err != nil {
// Resource does not exist yet, no validation needed
return nil
}
Change to:
// The name must be rce is new and has nothingcompare against.
if p.options.Control
if err := (resource.Controller{Name: p.options.ControllerName}).
err != nil {
return fmt.Errorf("invalid '--controller-name': %w", err
}
}
existingRes, err := p.config.GetResource(p.resource.GVK)
if err != nil {
// Resource does not exist yet, no further validation needed
return nil
}
|
Hi @onkar717 We use the PR title as release notes, I hope that you do not mind I tried to change it for users POV. Could you please check it out? if you think that has a better wording please feel free to change it too. |
--controller-name is invalid instead of failing silently
There was a problem hiding this comment.
Pull request overview
This PR fixes a correctness gap in the Go plugins’ controller scaffolding flow by ensuring invalid --controller-name values fail fast instead of being silently ignored and falling back to the default controller name.
Changes:
- Change
Options.UpdateResource/updateControllersto returnerrorand propagateControllers.AddControllervalidation/duplicate errors. - Propagate and wrap
UpdateResourceerrors at thecreate api/create webhookcall sites (including deploy-image). - Add unit tests covering valid, invalid, and duplicate
ControllerNamescenarios; update existing tests to assertUpdateResourcesuccess.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/plugins/golang/options.go | Return/propagate errors from controller updates instead of discarding AddController results. |
| pkg/plugins/golang/v4/api.go | Handle UpdateResource errors and return a wrapped failure instead of continuing. |
| pkg/plugins/golang/v4/webhook.go | Handle UpdateResource errors and return a wrapped failure instead of continuing. |
| pkg/plugins/golang/deploy-image/v1alpha1/api.go | Handle UpdateResource errors in deploy-image API scaffolding path. |
| pkg/plugins/golang/options_test.go | Add ControllerName validation tests and update existing cases to assert UpdateResource succeeds. |
|
I think we need move with #5941 |
Description
updateControllersinpkg/plugins/golang/options.godiscarded both calls toControllers.AddControllerwith_ =.AddControllervalidates the name as a DNS-1035 label and rejects duplicates, but the error was never propagated anywhere.validateControllerinpkg/plugins/golang/v4/api.goonly checks emptiness/duplicates against the resource already persisted in the PROJECT file, and never runs its format check for a brand-new resource (p.config.GetResourcereturns an error for a resource that doesn't exist yet, sovalidateControllerreturnsnilimmediately).Net effect: for a new API, an invalid
--controller-name(e.g.Backup_Ctrl, which fails DNS-1035 validation uppercase/underscore not allowed) was silently discarded.res.Controllersstayed empty, and the scaffolding logic inapi.gofell back to the default kind-derived controller name instead, while the CLI reported success. The user's chosenname was silently ignored.
Found this by reading the controller-scaffolding path end to end while looking for real, self-contained bugs to contribute. It's a genuine correctness gap (not defensive-only) reachable by any snake_case or otherwise-invalid
--controller-nameon first use, and the affected file had zero test coverage forControllerNameat all beforehand.What this PR does
updateControllersandUpdateResource(pkg/plugins/golang/options.go) now returnerrorand propagate bothAddControllercalls instead of discarding them.pkg/plugins/golang/v4/api.go,pkg/plugins/golang/v4/webhook.go,pkg/plugins/golang/deploy-image/v1alpha1/api.go), wrapped as"error updating resource: %w"to match the existing convention already used right below each of those call sites.ControllerName validationtest block inoptions_test.go: valid name (succeeds, controller added), invalid name (returns an error,Controllersstays empty instead of silently falling back), and duplicate name (returns an error).options.UpdateResource(...)calls in the same test file to assertSucceed(), since they now discard the same class of error the production code used to.Verified locally:
go build ./..., thegolang/v4/deploy-imageGinkgo suites all pass,golangci-lint run(pinned v2.12.2, repo config) reports 0 issues. Also verified the new tests aren't vacuous by temporarily reverting the fix both the "invalid name" and "duplicate name" cases went red with the expected failure messages, then passed again after revertingback.
Fixes: none filed this PR is the record; happy to file one if a maintainer would prefer it tracked separately.