fix(meta): RemoveFinalizer handles duplicate finalizers without panicking#1048
fix(meta): RemoveFinalizer handles duplicate finalizers without panicking#1048arpitjain099 wants to merge 1 commit into
Conversation
…king RemoveFinalizer mutated the finalizer slice in place while ranging over it by index. range evaluates len(f) once at loop start, but the append(f[:i], f[i+1:]...) call shrinks f in place, so after a removal the loop keeps walking original indices into the now-shorter backing array. When the target finalizer appears more than once this either panics with slice bounds out of range or silently leaves one occurrence behind. Replace the index-mutating loop with slices.DeleteFunc, which removes all matching elements correctly in a single pass. The slices package is already imported and used by the sibling AddFinalizer/FinalizerExists. Add regression cases for duplicate finalizers to TestRemoveFinalizer. Signed-off-by: Arpit Jain <arpitjain099@gmail.com>
📝 WalkthroughWalkthrough
ChangesRemoveFinalizer duplicate handling
Estimated code review effort🎯 1 (Trivial) | ⏱️ ~3 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
pkg/meta/meta_test.go (1)
541-562: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winCould we add a
reasonfield to these new cases?That would keep the duplicate scenarios aligned with the repo’s table-driven test convention and make failures easier to interpret. Thanks for adding the regression coverage here.
Example update
cases := map[string]struct { + reason string args args want []string }{ "DuplicateFinalizersExist": { + reason: "RemoveFinalizer should remove every matching duplicate entry", args: args{ o: &corev1.Pod{ ObjectMeta: metav1.ObjectMeta{ Finalizers: []string{finalizer, finalizer}, }, }, finalizer: finalizer, }, want: []string{}, }, "DuplicateFinalizersWithOther": { + reason: "RemoveFinalizer should preserve non-matching finalizers while removing duplicate matches", args: args{ o: &corev1.Pod{ ObjectMeta: metav1.ObjectMeta{ Finalizers: []string{finalizer, funalizer, finalizer}, }, }, finalizer: finalizer, }, want: []string{funalizer}, }, }As per path instructions,
**/*_test.go: Enforce table-driven test structure: PascalCase test names (no underscores), args/want pattern, use cmp.Diff with cmpopts.EquateErrors() for error testing. Check for proper test case naming and reason fields.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@pkg/meta/meta_test.go` around lines 541 - 562, Add a reason field to the new table-driven cases in the meta test table so they match the repo’s test convention and are easier to diagnose when they fail. Update the DuplicateFinalizersExist and DuplicateFinalizersWithOther entries in the test case list to include a concise reason string, keeping the existing args and want structure unchanged. Use the surrounding table-driven pattern in the meta test to keep the new cases consistent with the rest of the suite.Source: Path instructions
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@pkg/meta/meta_test.go`:
- Around line 541-562: Add a reason field to the new table-driven cases in the
meta test table so they match the repo’s test convention and are easier to
diagnose when they fail. Update the DuplicateFinalizersExist and
DuplicateFinalizersWithOther entries in the test case list to include a concise
reason string, keeping the existing args and want structure unchanged. Use the
surrounding table-driven pattern in the meta test to keep the new cases
consistent with the rest of the suite.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: ab4d406d-80c2-4a42-8b81-007ea282b00a
📒 Files selected for processing (2)
pkg/meta/meta.gopkg/meta/meta_test.go
Description of your changes
RemoveFinalizerin pkg/meta deletes from the finalizer slice in place while ranging over it by index, which is the classic delete-while-ranging bug:rangefixes the length at loop start butappend(f[:i], f[i+1:]...)shrinksfunderneath it, so after one removal the loop keeps indexing into a now-shorter slice. When the finalizer appears more than once this either panics (["fin","fin"]) or silently leaves a copy behind (["fin","fin","fun"]returns["fin","fun"]). It backsAPIFinalizer.RemoveFinalizeron the managed-resource deletion path, so a duplicate finalizer (concurrent reconciles, patch races, version skew) can crash a controller during deletion or leave it stuck Terminating, which lines up with #1010.AddFinalizeralready dedupes withslices.Contains; this side didn't.Swapped the loop for
slices.DeleteFunc, which removes all matches in one pass.slicesis already imported here, so no new deps. Added two duplicate cases toTestRemoveFinalizer; they panic before the change and pass after.go test -race ./pkg/meta/...,go vet ./pkg/meta/..., andgo build ./...are all green.I have:
Run(ran./nix.sh flake checkto ensure this PR is ready for review.go test -race,go vet, andgo build ./...directly; happy to run flake check if needed)Linked a PR or a docs tracking issue to document this change.(internal helper, no user-facing docs)Added(deferring to maintainers on backport scope)backport release-x.ylabels to auto-backport this PR.