Skip to content

fix: strip stale system labels from release labels on upgrade - #32421

Open
bhuvan-somisetty wants to merge 2 commits into
helm:mainfrom
bhuvan-somisetty:fix/filter-system-labels-on-upgrade
Open

fix: strip stale system labels from release labels on upgrade#32421
bhuvan-somisetty wants to merge 2 commits into
helm:mainfrom
bhuvan-somisetty:fix/filter-system-labels-on-upgrade

Conversation

@bhuvan-somisetty

@bhuvan-somisetty bhuvan-somisetty commented Jul 21, 2026

Copy link
Copy Markdown

Summary

  • helm upgrade fetches the previous release via LastQuery, and the k8s Secrets/ConfigMaps drivers' List/Query return release labels straight from the object's labels (unlike Get, which strips system labels via filterSystemLabels).
  • mergeCustomLabels (pkg/action/upgrade.go) then merged those labels into the new release's Labels without stripping the system ones (name, owner, status, version, createdAt, modifiedAt), so each new revision inherited the previous revision's createdAt/modifiedAt, and the release body's .Labels map permanently accumulated system-label keys.
  • Fix: strip system labels inside mergeCustomLabels itself, right where the previous release's labels get folded into the new one.

Note on approach: an earlier version of this PR filtered system labels directly in Secrets.List/Query and ConfigMaps.List/Query to mirror Get. That was reverted — helm list --selector matches against the labels List/Query return (pkg/action/list.go filterSelector), so filtering there would silently break selectors like -l owner=helm or -l status=deployed. Fixing it in mergeCustomLabels instead only changes what upgrade persists, leaving List/Query/selector behavior untouched.

Fixes #32404

Test plan

  • go test ./pkg/action/... and go test ./pkg/storage/driver/... pass
  • TestMergeCustomLabels covers a stale system label riding in via current and confirms it's stripped from the merged result
  • TestUpgradeRelease_Labels / TestUpgradeRelease_SystemLabels still pass unchanged
  • TestSecretList/TestSecretQuery/TestConfigMapList/TestConfigMapQuery are back to their original assertions (system labels still present in List/Query results, preserving selector behavior)

Secrets.List/Query and ConfigMaps.List/Query returned the raw object
labels, including system labels (name, owner, status, version,
createdAt, modifiedAt), unlike Get which already filters them. This
let system labels ride along in lastRelease.Labels on upgrade and get
merged into the new release, permanently baking stale createdAt values
and system-label keys into the stored release body.

Fixes helm#32404

Signed-off-by: bhuvan-somisetty <somisettybhuvan5@gmail.com>
Copilot AI review requested due to automatic review settings July 21, 2026 15:47
@pull-request-size pull-request-size Bot added the size/M Denotes a PR that changes 30-99 lines, ignoring generated files. label Jul 21, 2026
@github-actions github-actions Bot added the v4.x Issues and Pull Requests related to the major version v4 label Jul 21, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aligns the Kubernetes storage drivers’ read paths (List/Query) with Get by filtering out Helm system labels from the returned release .Labels, preventing those labels from being carried forward and merged into subsequent upgrades.

Changes:

  • Apply filterSystemLabels(...) to Secrets.List/Secrets.Query results.
  • Apply filterSystemLabels(...) to ConfigMaps.List/ConfigMaps.Query results.
  • Update Secrets/ConfigMaps driver tests to assert List/Query do not return system labels (e.g., name) in rls.Labels.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
pkg/storage/driver/secrets.go Filters system labels from .Labels in List and Query to match Get.
pkg/storage/driver/secrets_test.go Updates list/query tests to assert system labels are not present in results.
pkg/storage/driver/cfgmaps.go Filters system labels from .Labels in List and Query to match Get.
pkg/storage/driver/cfgmaps_test.go Updates list/query tests to assert system labels are not present in results.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@Mukuwul

Mukuwul commented Jul 21, 2026

Copy link
Copy Markdown

Thanks for jumping on this so fast @bhuvan-somisetty, and it's a clean diff — this does fix the upgrade path I reported (LastQuery no longer drags the stale system labels into the merge).

One thing I'd want a maintainer to sign off on before it lands, though: filtering in List/Query also changes what helm list --selector matches against. filterSelector runs the user's -l selector over rls.Labels (pkg/action/list.go:293, selector.Matches(labels.Set(rls.Labels))), so today helm list -l owner=helm / -l version=2 / -l status=deployed actually match on those system labels. After this change they'd quietly stop matching, since the keys are gone from the list results. That's the behaviour the old TestSecretList comment ("needed to ensure that selector filtering would work") was pinning — probably don't want to drop it by accident.

That interaction is actually why I left the issue asking where the filter should live instead of sending a PR myself — the candidate spots have pretty different blast radius:

  • Query/List (this PR): fixes the leak, but also hides system labels from helm list --selector.
  • mergeCustomLabels in upgrade.go: scoped to the upgrade path, leaves read/selector behaviour untouched.
  • the write side (Create / newSecretsObject): stops the stale value ever being persisted, and would also cover the latent double-fromMap at secrets.go:260 that can clobber a fresh createdAt regardless of where the labels came in from.

Not saying mirroring Get is the wrong call — just that the selector bit makes it a backward-compat decision a maintainer should make on purpose. Happy to help test whichever direction gets picked.

@bhuvan-somisetty

Copy link
Copy Markdown
Author

Hey @TerryHowe @gjenkins8 @mattfarina @robertsirc — whenever you get a chance, would appreciate a look at this one. Also looks like the CI workflows (CodeQL/build-test/golangci-lint) are stuck in action_required since it's coming from a fork, so if one of you could approve those runs too that'd help get everything green. Thanks!

…Query

Filtering system labels in the k8s drivers' List/Query (as done in the
previous commit) also strips them from helm list --selector results,
since filterSelector matches against rls.Labels. That silently breaks
`helm list -l owner=helm`, `-l status=deployed`, etc., which currently
rely on List/Query returning system labels alongside custom ones.

Move the fix to where the leak actually turns into a stored value:
mergeCustomLabels in the upgrade path, which is what folds the previous
release's labels into the new one. Stripping system labels there keeps
List/Query/selector behavior unchanged while still preventing stale
createdAt/modifiedAt and system-label keys from being carried into the
new release's persisted Labels.

Fixes helm#32404

Signed-off-by: bhuvan-somisetty <somisettybhuvan5@gmail.com>
Copilot AI review requested due to automatic review settings July 21, 2026 16:40
@pull-request-size pull-request-size Bot added size/S Denotes a PR that changes 10-29 lines, ignoring generated files. and removed size/M Denotes a PR that changes 30-99 lines, ignoring generated files. labels Jul 21, 2026
@bhuvan-somisetty

bhuvan-somisetty commented Jul 21, 2026

Copy link
Copy Markdown
Author

@Mukuwul Good catch, thanks — you're right, I hadn't traced it through to filterSelector. Just pushed a fix that moves the filtering out of List/Query entirely and instead strips system labels in mergeCustomLabels (pkg/action/upgrade.go), which is where the leak actually turns into a persisted value on upgrade. That leaves rls.Labels from List/Query untouched, so helm list --selector against owner/status/version keeps working exactly as before, and the old TestSecretList/TestConfigMapList assertions are back to their original form. Added a case to TestMergeCustomLabels covering a stale system label riding in via current and confirmed TestUpgradeRelease_Labels/TestUpgradeRelease_SystemLabels still pass.

Went with this over the write-side (Create/newSecretsObject) option since it's the narrowest change that fixes both symptoms you listed without touching the double-fromMap behavior elsewhere — but happy to reconsider if a maintainer prefers the write-side fix instead.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment thread pkg/action/upgrade.go
Comment on lines +664 to +670
// current comes from the previously stored release, which the k8s
// drivers (unlike Get) return with system labels still attached; strip
// them here so they don't ride along into the new release's Labels and
// clobber the fresh createdAt/modifiedAt set when it's persisted.
for _, k := range driver.GetSystemLabels() {
delete(labels, k)
}
@bhuvan-somisetty bhuvan-somisetty changed the title fix: filter system labels from release labels in List/Query fix: strip stale system labels from release labels on upgrade Jul 21, 2026
@bhuvan-somisetty

Copy link
Copy Markdown
Author

Fair point — the description was stale from before I switched approaches. Went with option (b): updated the title/description just now to reflect that the actual fix lives in mergeCustomLabels, not the drivers. Left List/Query untouched on purpose — filtering there breaks helm list --selector against system labels (owner, status, etc.), which @Mukuwul flagged above. Good callout, thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/S Denotes a PR that changes 10-29 lines, ignoring generated files. v4.x Issues and Pull Requests related to the major version v4

Projects

None yet

Development

Successfully merging this pull request may close these issues.

helm upgrade carries the previous revision's system labels (createdAt/modifiedAt/...) into the new release

3 participants