diff --git a/CHANGELOG.md b/CHANGELOG.md index c8b519356ee..fb4a2c41047 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -93,6 +93,7 @@ * [BUGFIX] Memberlist: Add `-memberlist.packet-read-timeout`, `-memberlist.max-packet-size`, and `-memberlist.max-concurrent-connections` flags to bound inbound gossip TCP connections, preventing slow-read, OOM, and connection-flood attacks on the gossip port. #7518 * [BUGFIX] Distributor: Add `WrappedHistogram` with configurable size limit (`-validation.max-native-histogram-size-bytes`, default 16 KB) to cap native histogram protobuf size before unmarshalling, preventing memory amplification attacks via packed varint deltas. #7570 * [BUGFIX] Distributor: Fix a panic (`slice bounds out of range`) in the stream push path when the context deadline expires while the worker goroutine is still marshalling a `WriteRequest`. #7541 +* [BUGFIX] Config: Fix CSV-list flags/YAML fields (e.g. `-compactor.enabled-tenants`, `-compactor.disabled-tenants`) treating an explicitly empty string (`""`) as a one-element list containing an empty tenant name instead of an empty list. This caused every tenant to be skipped when `enabled_tenants: ""` was set in config, since only the (nonexistent) empty-string tenant matched the allow-list. #6581 ## 1.21.0 2026-04-24 diff --git a/pkg/util/flagext/stringslicecsv.go b/pkg/util/flagext/stringslicecsv.go index 1f1aff6f1c3..0fd91efe7bf 100644 --- a/pkg/util/flagext/stringslicecsv.go +++ b/pkg/util/flagext/stringslicecsv.go @@ -13,6 +13,10 @@ func (v StringSliceCSV) String() string { // Set implements flag.Value func (v *StringSliceCSV) Set(s string) error { + if s == "" { + *v = nil + return nil + } *v = strings.Split(s, ",") return nil } diff --git a/pkg/util/flagext/stringslicecsv_test.go b/pkg/util/flagext/stringslicecsv_test.go index 67e50ba1df4..f65f669fa71 100644 --- a/pkg/util/flagext/stringslicecsv_test.go +++ b/pkg/util/flagext/stringslicecsv_test.go @@ -32,3 +32,21 @@ func Test_StringSliceCSV(t *testing.T) { assert.Nil(t, err) assert.Equal(t, testStruct, testStruct2) } + +func Test_StringSliceCSV_Empty(t *testing.T) { + var v StringSliceCSV + assert.Nil(t, v.Set("")) + assert.Equal(t, []string(nil), []string(v)) + assert.Len(t, v, 0) +} + +func Test_StringSliceCSV_UnmarshalYAML_Empty(t *testing.T) { + type TestStruct struct { + CSV StringSliceCSV `yaml:"csv"` + } + + var testStruct TestStruct + err := yaml.Unmarshal([]byte(`csv: ""`), &testStruct) + assert.Nil(t, err) + assert.Len(t, testStruct.CSV, 0) +}