refactor(kube): replace manual GVR pluralization with REST mapper#170
refactor(kube): replace manual GVR pluralization with REST mapper#170
Conversation
GetResourceGVR used naive `kind + "s"` which produced "policys" for Policy/ClusterPolicy. The dynamic client then hit a 404, causing ApplyManifest to silently skip Kyverno policies and leave challenges unprotected. Add a pluralize() helper that maps "-y" → "-ies" and use it as the default. Existing explicit switch cases (networkpolicies, endpoints, ingresses) are unchanged. Add TestGetResourceGVR cases for kyverno.io/Policy and kyverno.io/ClusterPolicy. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Claude finished @pbrissaud's task in 1m 51s —— View job PR Review: fix(kube): correct pluralization for kinds ending in -y
SummaryThe fix correctly addresses the root cause: Overall verdict: approve with minor notes. Findings1. Potential over-broad
|
internal/kube/client.go
Outdated
| return kind[:len(kind)-1] + "ies" | ||
| } | ||
| return kind + "s" | ||
| } |
There was a problem hiding this comment.
Potential over-broad pluralization rule
The current rule applies y → ies to all kinds ending in y, including those ending in a vowel+y (e.g., Relay → relaies, Key → kies, Monkey → monkies). For standard Kubernetes resources this is fine — none end in vowel+y — but 3rd-party CRDs could be affected.
The proper English rule is: only replace y with ies when the preceding letter is a consonant.
| } | |
| func pluralize(kind string) string { | |
| if strings.HasSuffix(kind, "y") && len(kind) >= 2 { | |
| prev := kind[len(kind)-2] | |
| if prev != 'a' && prev != 'e' && prev != 'i' && prev != 'o' && prev != 'u' { | |
| return kind[:len(kind)-1] + "ies" | |
| } | |
| } | |
| return kind + "s" | |
| } |
This is a low-risk edge case for this project's current scope, but worth considering for robustness.
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
…h cases - pluralize() now only applies the y→ies transform when the preceding character is a consonant, preventing incorrect plurals for CRDs with vowel-y endings (e.g. relay → relays, not relaies) - Remove networkpolicy and podsecuritypolicy switch cases: pluralize() already handles them correctly, so the explicit overrides were dead code - Add TestPluralize unit test covering consonant-y, vowel-y, and non-y cases Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Claude finished @pbrissaud's task in 1m 22s —— View job PR Review (updated): fix(kube): correct pluralization for kinds ending in -y
All three concerns from the previous review have been addressed in the latest commit ( What changed in the latest commit1. ✅ Consonant-y restriction added (previously flagged as over-broad) The var vowels = map[byte]bool{'a': true, 'e': true, 'i': true, 'o': true, 'u': true}
func pluralize(kind string) string {
if strings.HasSuffix(kind, "y") && len(kind) >= 2 && !vowels[kind[len(kind)-2]] {
return kind[:len(kind)-1] + "ies"
}
return kind + "s"
}
2. ✅ Redundant switch cases removed
3. ✅ Unit tests for
Minor observations (non-blocking)
SummaryThe fix is correct, minimal, and well-tested. All previous feedback incorporated. Ready to merge. |
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Claude finished @pbrissaud's task in 1m 54s —— View job PR Review (updated): fix(kube): correct pluralization for kinds ending in -y
SummaryAll feedback from the initial review has been addressed in the two follow-up commits. The PR is in excellent shape. Here's the full analysis of the current state. What changed since the last reviewCommit
Commit
Current implementation (
|
Remove GetResourceGVR, pluralize, vowels, and IsNamespaced. ApplyManifest now accepts a meta.RESTMapper and resolves GVR + scope via mapper.RESTMapping(), eliminating the hardcoded special-case switch. Deployers build the mapper once from clientset.Discovery() before applying manifests. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Claude finished @pbrissaud's task in 2m 30s —— View job PR Review: refactor(kube): replace manual GVR pluralization with REST mapper
This is a solid architectural improvement. Replacing the manual What the refactor does
Findings1. Stale mapper within
|
- Add comment in SetupInfrastructure explaining the mapper is a point-in-time snapshot and why that is safe for these manifests - Align challenge.go to accept both .yaml and .yml files, matching the behaviour already present in local.go Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Claude finished @pbrissaud's task in 1m 33s —— View job PR Review: refactor(kube): replace manual GVR pluralization with REST mapper
This PR is in excellent shape. All findings from previous review cycles have been incorporated, including the latest commit ( What the latest commit (
|
Summary
GetResourceGVRused naive manual pluralization (switch +pluralize()helper), requiring a hardcoded list of special cases and producing wrong results for edge cases likeKind: Endpoints→endpointssmeta.RESTMapper.RESTMapping(): GVR and scope are now resolved directly from the cluster's API discovery, with zero special cases in codeIsNamespacedhardcoded list replaced bymapping.Scope.Name() == meta.RESTScopeNameNamespaceClusterPolicy, etc.) now resolve automatically without any code changesChanges
internal/kube/manifest.go:ApplyManifestnow acceptsmeta.RESTMapperinstead of*kubernetes.Clientset; usesmapper.RESTMapping()for GVR + scope;IsNamespacedremovedinternal/kube/client.go: Removedpluralize,vowels,GetResourceGVR(~50 lines)internal/deployer/infrastructure.go: Builds mapper viarestmapper.GetAPIGroupResources(clientset.Discovery())once before applying manifestsinternal/deployer/challenge.go: Sameinternal/deployer/local.go: Sameinternal/kube/manifest_test.go: ReplacedTestIsNamespacedandTestApplyManifest_NilClientsetwithtestrestmapper-based tests; addedTestApplyManifest_RESTMapperGVRandTestApplyManifest_RESTMapperScopeinternal/kube/client_test.go: RemovedTestPluralizeandTestGetResourceGVRTest plan
TestApplyManifest_RESTMapperGVR— verifies Deployment, ClusterRole, ServiceAccount resolve to correct GVRs via mapperTestApplyManifest_RESTMapperScope— verifies ClusterRole (cluster-scoped) gets no namespace injected; ServiceAccount (namespaced) doesTestApplyManifest_ErrorHandling/skips_unknown_kinds_gracefully— unknown kinds (e.g. Kyverno CRDs not in scheme) are logged and skipped without errorTestApplyManifest_*tests passtask lint— 0 issuestask build— clean build🤖 Generated with Claude Code