Skip to content

Prefer helm dependency build over dependency up when Chart.lock exists#185

Open
sstarcher wants to merge 1 commit into
helmfile:masterfrom
sstarcher:prefer-dep-build-over-up
Open

Prefer helm dependency build over dependency up when Chart.lock exists#185
sstarcher wants to merge 1 commit into
helmfile:masterfrom
sstarcher:prefer-dep-build-over-up

Conversation

@sstarcher
Copy link
Copy Markdown

Problem

When chartify is engaged (e.g. helmfile invokes it for releases that use jsonPatches, strategic-merge patches, or kustomize), it copies the chart to a temp dir and runs helm dependency up before rendering. dep up re-resolves from Chart.yaml's version constraints and rewrites Chart.lock, so any constraint that allows newer versions (e.g. version: "*" or ~4.1.0) silently pulls a newer dependency on every render.

This is asymmetric with the rest of the helmfile pipeline. Helmfile's non-chartify code path (pkg/helmexec/exec.go BuildDeps) uses helm dependency build, which honors the lock. The result: adding an unrelated jsonPatches block to a release can flip a chart from "locked rendering" to "latest matching constraint rendering," producing surprising image/version drift downstream.

We hit this with aws-efs-csi-driver — the chart had version: "*", a committed Chart.lock pinning 4.1.0, and a kustomization-patch.yaml. helm template rendered v3.1.0 (the locked appVersion), but helmfile template rendered v3.2.0 because chartify ran dep up and re-resolved to 4.2.0.

Change

In Chartify()'s local-chart branch:

  • If Chart.lock (or legacy requirements.lock) exists and no adhoc deps were injected, run helm dependency build instead of up.
  • If build fails (typically because the lock is out of sync with Chart.yaml), log a fallback and run up. Preserves the existing escape hatch for charts whose lock has drifted.
  • No lock file or adhoc deps present → unchanged (up).

Adhoc deps still use up because they're appended to Chart.yaml after the lock was generated; build would fail with "lock out of sync."

Compatibility

Backward compatible:

  • Charts without a lock: same behavior.
  • Charts with a stale lock: fallback runs up, behavior matches today.
  • Charts with a valid lock: now reproducible. This is the desirable change.

Test

Adds TestHasChartLock covering presence/absence of Chart.lock and requirements.lock. Existing integration tests pass (two unrelated pre-existing failures on master — kube_version_and_api_versions snapshot drift and a kubeconfig-namespace leak — are not affected by this change).

@sstarcher
Copy link
Copy Markdown
Author

This won't work due to chartify rewriting Chart.yaml which would invalidate the lock

@sstarcher sstarcher closed this May 13, 2026
@sstarcher sstarcher reopened this May 13, 2026
@sstarcher
Copy link
Copy Markdown
Author

This looks to be working if in helmfile we also update the Chart.lock's SHA when we rewrite the path

…xists

When chartify is engaged (e.g. helmfile invokes it for releases that use
jsonPatches, strategic-merge patches, or kustomize), it copies the chart
to a temp directory and runs `helm dependency up` to flatten dependencies
before rendering. `dep up` re-resolves from Chart.yaml's version
constraints and rewrites Chart.lock, which silently pulls newer
dependency versions whenever constraints permit (e.g. `version: "*"`).

This diverges from helmfile's non-chartify code path
(pkg/helmexec/exec.go `BuildDeps`), which calls `helm dependency build`
and honors the lock. The asymmetry means an unrelated change like
adding a `jsonPatches` block to a release can flip a chart from
locked-version rendering to "latest matching constraint" rendering,
producing surprising image/version drift.

Behavior change:

- If `Chart.lock` (or legacy `requirements.lock`) exists and no adhoc
  chart dependencies were injected, run `helm dependency build`. This
  resolves dependencies from the lock and matches the rest of the
  helmfile pipeline.
- If `dependency build` fails (typically because the lock is out of
  sync with Chart.yaml), fall back to `dependency up` and log the
  fallback. This preserves the previous escape hatch for charts whose
  lock has drifted.
- If no lock file exists, or adhoc dependencies are present, behavior
  is unchanged — still `dependency up`.

Adds a unit test for the lock-file detection helper.

Signed-off-by: Shane Starcher <shane.starcher@gmail.com>
@sstarcher sstarcher force-pushed the prefer-dep-build-over-up branch from a9c7158 to d883b8d Compare May 13, 2026 18:50
@sstarcher
Copy link
Copy Markdown
Author

This MR paired with this change helmfile/helmfile#2587 fixes my root issue of Chart.locks being ignored and auto updated.

Copy link
Copy Markdown

Copilot AI left a comment

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 changes chart dependency resolution in Chartify so local charts with lock files prefer reproducible Helm dependency builds over dependency updates.

Changes:

  • Adds lock-file detection for Chart.lock and legacy requirements.lock.
  • Switches local-chart dependency resolution to helm dependency build when a lock exists and no adhoc deps are injected.
  • Adds unit coverage for the lock-file detection helper.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
chartify.go Updates local chart dependency command selection and adds hasChartLock.
util_test.go Adds tests for hasChartLock lock-file detection.

Comment thread chartify.go
//
// Adhoc dependencies are appended to Chart.yaml after the lock was generated, so the lock
// is by definition out of sync — `build` would fail. Fall back to `up` in that case.
useBuild := len(u.AdhocChartDependencies) == 0 && hasChartLock(tempDir)
Comment thread chartify.go
Comment on lines +407 to +412
if err != nil && useBuild {
// `helm dependency build` errors when Chart.lock is out of sync with Chart.yaml.
// Fall back to `up` so chartify keeps working on charts whose lock has drifted.
r.Logf("`helm dependency build` failed for release %s, falling back to `helm dependency up`: %v", release, err)
depArgs[1] = "up"
_, err = r.run(nil, r.helmBin(), depArgs...)
Comment thread chartify.go
Comment on lines +407 to +412
if err != nil && useBuild {
// `helm dependency build` errors when Chart.lock is out of sync with Chart.yaml.
// Fall back to `up` so chartify keeps working on charts whose lock has drifted.
r.Logf("`helm dependency build` failed for release %s, falling back to `helm dependency up`: %v", release, err)
depArgs[1] = "up"
_, err = r.run(nil, r.helmBin(), depArgs...)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants