Skip to content

Fix CIDRSliceCSV appending to the previous value instead of replacing it - #7831

Open
youdie006 wants to merge 2 commits into
cortexproject:masterfrom
youdie006:cidr-slice-csv-set-replaces
Open

Fix CIDRSliceCSV appending to the previous value instead of replacing it#7831
youdie006 wants to merge 2 commits into
cortexproject:masterfrom
youdie006:cidr-slice-csv-set-replaces

Conversation

@youdie006

Copy link
Copy Markdown

What this PR does:

CIDRSliceCSV.Set (pkg/util/flagext/cidr.go:48) did *c = append(*c, *cidr), accumulating onto whatever the value already held instead of replacing it.

That matters because Limits.UnmarshalYAML (pkg/util/validation/limits.go:489) sets the value to the defaults and then unmarshals the tenant's YAML on top — its own comment states the invariant: "We want to set l to the defaults and then overwrite it with the input." For alertmanager_receivers_firewall_block_cidr_networks the override was appended instead, so a tenant got operator defaults plus its own list, and CIDRs it removed from the list stayed blocked.

Measured through Overrides.AlertmanagerReceiversBlockCIDRNetworks (limits.go:1123), the value the Alertmanager receiver firewall dialer reads at pkg/alertmanager/alertmanager.go:668:

defaults:  10.0.0.0/8, 192.168.0.0/16
tenant YAML: alertmanager_receivers_firewall_block_cidr_networks: 172.16.0.0/12

before: [10.0.0.0/8 192.168.0.0/16 172.16.0.0/12]
after:  [172.16.0.0/12]

This fails closed — it over-blocks rather than under-blocks — so it is a config-correctness bug, not a security issue.

The two siblings in the same package

implementation behaviour on a second Set
stringslicecsv.go:15 StringSliceCSV.Set *v = strings.Split(s, ",") — replaces
secretstringslicecsv.go:23 SecretStringSliceCSV.Set builds values, then v.values = values — replaces
cidr.go:48 CIDRSliceCSV.Set appended

The fix follows SecretStringSliceCSV exactly: build into a fresh slice, assign at the end. That also makes a failed entry leave the existing value untouched, which the append version did not — it kept whatever it had already parsed before the error.

Not changed: Set("") still returns cidr: : invalid CIDR address: and leaves the value alone, exactly as on master. #7714 gave StringSliceCSV an explicit empty-string case; whether CIDRSliceCSV should get one too is a separate question and I left it out of this change.

Which issue(s) this PR fixes:
No existing issue; found by reading the three CSV slice types in pkg/util/flagext against each other.

Testing

  • Test_CIDRSliceCSV_SetReplacesPreviousValue and Test_CIDRSliceCSV_SetDoesNotMutateOnError in cidr_test.go, plus TestAlertmanagerReceiversBlockCIDRNetworksPerTenantOverrideReplacesDefault in limits_test.go, which drives the real YAML → Overrides path.
  • All three fail on master. The consumer test fails with expected: []string{"172.16.0.0/12"} / actual: []string{"10.0.0.0/8", "192.168.0.0/16", "172.16.0.0/12"}.
  • Mutation-checked in both directions. Restoring the append brings all three failures back. Over-correcting by clearing eagerly (*c = nil up front) fails SetDoesNotMutateOnError with actual: "", and committing partial values on the error path fails it with actual: "192.168.0.0/16" — so the atomicity side is pinned too.
  • go test -tags "netgo slicelabels" -timeout 30m -race -count 1 ./pkg/util/... ./pkg/alertmanager/... passes.
  • golangci-lint run reports 0 issues, run as v2.13.1 built with go1.27.0 inside quay.io/cortexproject/build-image:master-7bc8b2491b so it matches the Lint job exactly. modernize@v0.23.0 clean, go vet clean, gofmt clean.

Test_CIDRSliceCSV_YamlMarshalling varies one axis — entry count — and every row starts from TestStruct{}, so nothing covered a second Set on a populated value.

Checklist

  • Tests updated
  • Documentation added
  • CHANGELOG.md updated - the order of entries should be [CHANGE], [FEATURE], [ENHANCEMENT], [BUGFIX]
  • docs/configuration/v1-guarantees.md updated if this PR introduces experimental flags

Per GENAI_POLICY.md: AI usage disclosure — this patch was found and written with Claude Code. I have reviewed every line and can explain it without going back to the tool. All output quoted above is verbatim from running it against master and against this branch.

CIDRSliceCSV.Set appended onto whatever the value already held, so a
per-tenant override of alertmanager_receivers_firewall_block_cidr_networks
was added on top of the operator defaults rather than replacing them.
Limits.UnmarshalYAML copies the defaults and then unmarshals the tenant's
YAML over them, so CIDRs a tenant removed from the list stayed blocked.

StringSliceCSV.Set and SecretStringSliceCSV.Set both assign. Build into a
fresh slice so the value replaces the previous one, and so a bad entry
leaves the existing value untouched.

Signed-off-by: manon <youdie006@users.noreply.github.com>
@youdie006
youdie006 requested a review from a team as a code owner September 8, 2026 10:04
@youdie006
youdie006 requested a review from yeya24 September 8, 2026 10:04
Signed-off-by: manon <youdie006@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant