Summary
ParseLabelSelector produces a NotIn expression with duplicate values when the same key appears in multiple != requirements. This breaks round-trip stability because the Kubernetes label parser uses a set internally, which silently drops duplicates.
Steps to reproduce
- Parse
"key!=,key!=" with ParseLabelSelector
- Format the result with
metav1.FormatLabelSelector -- produces "key notin (,)" (two empty strings joined by comma)
- Parse
"key notin (,)" again -- the Kubernetes parser stores values in a set, so the two empty strings collapse to one
- Format again -- produces
"key notin ()" instead of "key notin (,)"
Root cause
lease_helpers.go:129 blindly appends to the notEqualsByKey slice without deduplicating:
notEqualsByKey[key] = append(notEqualsByKey[key], values[0])
When the same key-value pair appears twice (e.g. key!=,key!=), the resulting Values slice contains ["", ""]. The Kubernetes labels.Parse function uses sets.String (a map) for values, which can only hold one copy of each value. So the first format is faithful to the slice, but the second parse deduplicates, and the second format reflects that.
Suggested fix
Deduplicate values in notEqualsByKey before building the NotIn expression, so the slice never contains duplicates that the set-based re-parser would collapse.
Found by
The FuzzParseLabelSelector fuzz test in PR #720.
Summary
ParseLabelSelectorproduces aNotInexpression with duplicate values when the same key appears in multiple!=requirements. This breaks round-trip stability because the Kubernetes label parser uses a set internally, which silently drops duplicates.Steps to reproduce
"key!=,key!="withParseLabelSelectormetav1.FormatLabelSelector-- produces"key notin (,)"(two empty strings joined by comma)"key notin (,)"again -- the Kubernetes parser stores values in a set, so the two empty strings collapse to one"key notin ()"instead of"key notin (,)"Root cause
lease_helpers.go:129blindly appends to thenotEqualsByKeyslice without deduplicating:When the same key-value pair appears twice (e.g.
key!=,key!=), the resultingValuesslice contains["", ""]. The Kuberneteslabels.Parsefunction usessets.String(a map) for values, which can only hold one copy of each value. So the first format is faithful to the slice, but the second parse deduplicates, and the second format reflects that.Suggested fix
Deduplicate values in
notEqualsByKeybefore building theNotInexpression, so the slice never contains duplicates that the set-based re-parser would collapse.Found by
The
FuzzParseLabelSelectorfuzz test in PR #720.