Skip to content

Support versioning-strategy for the helm ecosystem (range-preserving updates) #15216

@casey-robertson-paypal

Description

@casey-robertson-paypal

Status (updated)

Implementation is up in #15218, with an end-to-end verification repo (runs the branch against real OCI charts across all strategies) and a companion docs PR github/docs#44584. The three "Open questions" in the original proposal below are addressed in the PR (per-ecosystem Helm::Requirement + RequirementsUpdater, used explicitly rather than globally registered; OCI resolution verified end-to-end).

One design decision is now in front of maintainers (details here): the original proposal below called increase "today's exact-pin behavior," but those turn out to be different things — helm's current exact-pin (^1.0.01.0.5) diverges from the documented, operator-preserving increase (^1.0.0^1.0.5). Whether the unset default should change for existing users is the open call. Prior art (Helm's own best-practices docs, Renovate, and every other Dependabot ecosystem) favors operator-preserving, but the backward-compat decision is the maintainers'. Original proposal preserved below for context.


Summary

The helm ecosystem always rewrites Chart.yaml dependency versions to the exact resolved version, ignoring the authored constraint. There's no way to preserve a range like ^2.0.0 and only bump it when the new version falls outside it.

This proposes wiring versioning-strategy into helm as it works for the npm-style ecosystems (e.g. npm, Bundler, pip, Composer): increase, increase-if-necessary, and widen. (See the Status note above: increase follows the documented operator-preserving semantics, which differs from helm's current exact-pin — whether the unset default should change is the open decision.)

Motivation

Exact-pin rewriting is fine when the same team authors and consumes a chart. It breaks down for shared internal charts: one platform team owns a base chart, many product repos consume it via Chart.yaml. Every patch the producer ships opens N PRs across N repos owned by the people with the least context on the change — so PRs sit stale (CVE fixes included), get rubber-stamped, or the producer does drive-by merges in other teams' repos.

Semver ranges exist to prevent exactly this: ^2.0.0 is the producer asserting "anything in 2.x is non-breaking." Range-preserving updates honor that:

  • in-range patch/minor → no PR; resolved on the next helm dependency update.
  • out-of-range (major) → PR opens — the producer's explicit "re-validate the integration" signal, and that review belongs on the consumer side.

Example

dependencies:
  - name: hr-cronjob
    version: ^1.0.0
  • Producer ships 1.0.5 → satisfied by ^1.0.0 → no PR (today: one PR per consumer repo, every patch).
  • Producer ships 2.0.0 → not satisfied → PR bumps the constraint to ^2.0.0.

Prior art

Renovate's rangeStrategy has done range-preserving Helm updates since 2019 (replaceincrease-if-necessary, widenwiden). Closing this gap removes a common reason to reach for Renovate.

Approach

  • Honor the requirements_update_strategy already passed to the update checker (the versioning-strategy → strategy mapping happens upstream of core).
  • Skip the update when the strategy is range-preserving and the new version already satisfies the constraint; otherwise rewrite the constraint per strategy instead of pinning.
  • One correctness note: Helm constraints are SemVer ranges (^, ~, ||), but helm currently registers a Gem-style requirement class and treats versions as opaque exact strings — so this needs a SemVer-aware requirement parser, modeled on npm's.
  • lockfile-only is N/A (Chart.lock is generated, not authored).
  • Docs follow-up: add helm to the versioning-strategy reference, which omits it today.

Happy to put up a draft PR once there's directional agreement.

Open questions

  1. Any architectural reason helm rewrites exact versions rather than reusing the shared versioning-strategy plumbing — i.e. is there a shared abstraction I should plug into rather than mirror per-ecosystem?
  2. Preference on duplicating the requirements-updater per-ecosystem (as today) vs. extracting a shared helper as part of this?
  3. Any concern about interaction with the existing OCI registry resolution path?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status
    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions