Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package helmfile for openSUSE:Factory 
checked in at 2026-08-06 16:20:54
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/helmfile (Old)
 and      /work/SRC/openSUSE:Factory/.helmfile.new.16738 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "helmfile"

Thu Aug  6 16:20:54 2026 rev:100 rq:1369624 version:1.7.3

Changes:
--------
--- /work/SRC/openSUSE:Factory/helmfile/helmfile.changes        2026-08-01 
18:38:12.186156740 +0200
+++ /work/SRC/openSUSE:Factory/.helmfile.new.16738/helmfile.changes     
2026-08-06 16:23:06.370333355 +0200
@@ -1,0 +2,24 @@
+Wed Aug  5 04:40:17 UTC 2026 - Manfred Hollstein <[email protected]>
+
+- Update to version 1.7.3:
+  * build(deps): bump docker/login-action from 4 to 4.5.2 by
+    @dependabot[bot] in #2723
+  * fix: skip chartification when chart renders zero resources by
+    @ankit090701 in #2724
+  * feat: add --skip-diff-validation-on-install CLI flag by
+    @henrichter-sap in #2728
+  * bump helm-diff to v3.15.11 by @yxxhero with @Copilot in #2725
+  * fix: update helm plugins via uninstall+reinstall to honor
+    pinned version by @yxxhero in #2727
+  * build(deps): bump docker/login-action from 4.5.2 to 4.6.0 by
+    @dependabot[bot] in #2729
+  * build(deps): bump gitpython from 3.1.54 to 3.1.57 in /docs by
+    @dependabot[bot] in #2730
+  * build(deps): bump github.com/aws/aws-sdk-go-v2/service/s3 from
+    1.106.2 to 1.106.3 by @dependabot[bot] in #2731
+  * build(deps): bump github.com/aws/aws-sdk-go-v2/config from
+    1.32.31 to 1.32.34 by @dependabot[bot] in #2732
+  * build(deps): bump github.com/helmfile/chartify from v0.28.0 to
+    v0.28.1 by @yxxhero in #2733
+
+-------------------------------------------------------------------

Old:
----
  helmfile-1.7.2.tar.gz

New:
----
  helmfile-1.7.3.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ helmfile.spec ++++++
--- /var/tmp/diff_new_pack.Odlwcs/_old  2026-08-06 16:23:08.266399574 +0200
+++ /var/tmp/diff_new_pack.Odlwcs/_new  2026-08-06 16:23:08.270399713 +0200
@@ -17,9 +17,9 @@
 #
 
 
-%define git_commit 7f748fec1b979a74aa7793e7a4d2f27944ad9748
+%define git_commit 5e68d499ecf3ef0bc92057f52fed4172b10d06d1
 Name:           helmfile
-Version:        1.7.2
+Version:        1.7.3
 Release:        0
 Summary:        Deploy Kubernetes Helm Charts
 License:        MIT

++++++ _service ++++++
--- /var/tmp/diff_new_pack.Odlwcs/_old  2026-08-06 16:23:08.326401669 +0200
+++ /var/tmp/diff_new_pack.Odlwcs/_new  2026-08-06 16:23:08.330401809 +0200
@@ -5,7 +5,7 @@
     <param name="exclude">.git</param>
     <param name="versionformat">@PARENT_TAG@</param>
     <param name="versionrewrite-pattern">v(.*)</param>
-    <param name="revision">v1.7.2</param>
+    <param name="revision">v1.7.3</param>
     <param name="changesgenerate">enable</param>
     <param name="changesauthor">[email protected]</param>
   </service>

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.Odlwcs/_old  2026-08-06 16:23:08.410404603 +0200
+++ /var/tmp/diff_new_pack.Odlwcs/_new  2026-08-06 16:23:08.418404882 +0200
@@ -1,7 +1,7 @@
 <servicedata>
 <service name="tar_scm">
   <param name="url">https://github.com/helmfile/helmfile.git</param>
-  <param 
name="changesrevision">7f748fec1b979a74aa7793e7a4d2f27944ad9748</param>
+  <param 
name="changesrevision">5e68d499ecf3ef0bc92057f52fed4172b10d06d1</param>
 </service>
 </servicedata>
 

++++++ helmfile-1.7.2.tar.gz -> helmfile-1.7.3.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helmfile-1.7.2/cmd/apply.go 
new/helmfile-1.7.3/cmd/apply.go
--- old/helmfile-1.7.2/cmd/apply.go     2026-07-31 16:22:31.000000000 +0200
+++ new/helmfile-1.7.3/cmd/apply.go     2026-08-04 12:31:11.000000000 +0200
@@ -50,6 +50,7 @@
        f.BoolVar(&applyOptions.EnforceNeedsAreInstalled, 
"enforce-needs-are-installed", false, "enforce that all 'needs' dependencies 
are installable before applying changes")
        f.BoolVar(&applyOptions.IncludeTransitiveNeeds, 
"include-transitive-needs", false, `like --include-needs, but also includes 
transitive needs (needs of needs). Does nothing when --selector/-l flag is not 
provided. Overrides exclusions of other selectors and conditions.`)
        f.BoolVar(&applyOptions.SkipDiffOnInstall, "skip-diff-on-install", 
false, "Skips running helm-diff on releases being newly installed on this 
apply. Useful when the release manifests are too huge to be reviewed, or it's 
too time-consuming to diff at all")
+       f.BoolVar(&applyOptions.SkipDiffValidationOnInstall, 
"skip-diff-validation-on-install", false, "Disables K8s API validation 
(--disable-validation) when running helm-diff on releases being newly 
installed. Useful when charts include CRDs and CRs in the same release")
        f.BoolVar(&applyOptions.IncludeTests, "include-tests", false, "enable 
the diffing of the helm test hooks")
        f.StringArrayVar(&applyOptions.Suppress, "suppress", nil, "suppress 
specified Kubernetes objects in the diff output. Can be provided multiple 
times. For example: --suppress KeycloakClient --suppress VaultSecret")
        f.BoolVar(&applyOptions.SuppressSecrets, "suppress-secrets", false, 
"suppress secrets in the diff output. highly recommended to specify on CI/CD 
use-cases")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helmfile-1.7.2/cmd/bind_diff_flags.go 
new/helmfile-1.7.3/cmd/bind_diff_flags.go
--- old/helmfile-1.7.2/cmd/bind_diff_flags.go   2026-07-31 16:22:31.000000000 
+0200
+++ new/helmfile-1.7.3/cmd/bind_diff_flags.go   2026-08-04 12:31:11.000000000 
+0200
@@ -32,6 +32,7 @@
        f.BoolVar(&opts.EnforceNeedsAreInstalled, 
"enforce-needs-are-installed", false, "enforce that all 'needs' dependencies 
are installable before applying changes")
        f.BoolVar(&opts.IncludeTransitiveNeeds, "include-transitive-needs", 
false, `like --include-needs, but also includes transitive needs (needs of 
needs). Does nothing when --selector/-l flag is not provided. Overrides 
exclusions of other selectors and conditions.`)
        f.BoolVar(&opts.SkipDiffOnInstall, "skip-diff-on-install", false, 
"Skips running helm-diff on releases being newly installed on this apply. 
Useful when the release manifests are too huge to be reviewed, or it's too 
time-consuming to diff at all")
+       f.BoolVar(&opts.SkipDiffValidationOnInstall, 
"skip-diff-validation-on-install", false, "Disables K8s API validation 
(--disable-validation) when running helm-diff on releases being newly 
installed. Useful when charts include CRDs and CRs in the same release")
        f.BoolVar(&opts.NoHooks, "no-hooks", false, "do not diff changes made 
by hooks.")
        f.BoolVar(&opts.StripTrailingCR, "strip-trailing-cr", false, "strip 
trailing carriage return on input")
        f.BoolVar(&opts.SuppressSecrets, "suppress-secrets", false, "suppress 
secrets in the output. highly recommended to specify on CI/CD use-cases")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helmfile-1.7.2/cmd/sync.go 
new/helmfile-1.7.3/cmd/sync.go
--- old/helmfile-1.7.2/cmd/sync.go      2026-07-31 16:22:31.000000000 +0200
+++ new/helmfile-1.7.3/cmd/sync.go      2026-08-04 12:31:11.000000000 +0200
@@ -74,6 +74,7 @@
        f.BoolVar(&syncOptions.NoHooks, "no-hooks", false, "do not diff changes 
made by hooks (interactive preview only)")
        f.BoolVar(&syncOptions.SuppressDiff, "suppress-diff", false, "suppress 
diff in the output (interactive preview only). Usable in new installs")
        f.BoolVar(&syncOptions.SkipDiffOnInstall, "skip-diff-on-install", 
false, "Skips running helm-diff on releases being newly installed on this sync 
(interactive preview only). Useful when the release manifests are too huge to 
be reviewed, or it's too time-consuming to diff at all")
+       f.BoolVar(&syncOptions.SkipDiffValidationOnInstall, 
"skip-diff-validation-on-install", false, "Disables K8s API validation 
(--disable-validation) when running helm-diff on releases being newly installed 
(interactive preview only). Useful when charts include CRDs and CRs in the same 
release")
        f.BoolVar(&syncOptions.IncludeTests, "include-tests", false, "enable 
the diffing of the helm test hooks (interactive preview only)")
        f.BoolVar(&syncOptions.DetailedExitcode, "detailed-exitcode", false, 
"return a non-zero exit code 2 instead of 0 when releases are synced (use 
--interactive to also see a diff preview)")
        f.BoolVar(&syncOptions.StripTrailingCR, "strip-trailing-cr", false, 
"strip trailing carriage return on input (interactive preview only)")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helmfile-1.7.2/docs/cli.md 
new/helmfile-1.7.3/docs/cli.md
--- old/helmfile-1.7.2/docs/cli.md      2026-07-31 16:22:31.000000000 +0200
+++ new/helmfile-1.7.3/docs/cli.md      2026-08-04 12:31:11.000000000 +0200
@@ -161,6 +161,11 @@
 you should be able to simply execute `helm plugin install 
https://github.com/databus23/helm-diff`. For more details
 please look at their 
[documentation](https://github.com/databus23/helm-diff#helm-diff-plugin).
 
+#### Notable diff flags
+
+* `--skip-diff-on-install` — skip running `helm diff` entirely for releases 
that are not yet installed. The release is treated as changed and will be 
synced on `apply` without showing a diff.
+* `--skip-diff-validation-on-install` — for releases that are not yet 
installed, pass `--disable-validation` to `helm diff` so the diff is shown 
without K8s API server validation. Useful when a chart bundles CRDs and CRs 
together: the CRs would fail API validation before the CRDs are installed. This 
is the CLI-flag equivalent of the per-release `disableValidationOnInstall` 
field.
+
 ### doctor
 
 `helmfile doctor` runs `helmfile diff` and asks an OpenAI-compatible LLM to 
summarize the changes and flag risks
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helmfile-1.7.2/docs/configuration.md 
new/helmfile-1.7.3/docs/configuration.md
--- old/helmfile-1.7.2/docs/configuration.md    2026-07-31 16:22:31.000000000 
+0200
+++ new/helmfile-1.7.3/docs/configuration.md    2026-08-04 12:31:11.000000000 
+0200
@@ -265,6 +265,7 @@
     # passes --disable-validation to helm diff plugin, this requires diff 
plugin >= 3.1.2
     # It is useful when any release contains custom resources for CRDs that is 
not yet installed onto the cluster.
     # https://github.com/roboll/helmfile/pull/1618
+    # To apply this to all releases without editing each one, use the 
--skip-diff-validation-on-install CLI flag.
     disableValidationOnInstall: false
     # passes --disable-openapi-validation to helm diff plugin, this requires 
diff plugin >= 3.1.2
     # It may be helpful to deploy charts with helm api v1 CRDS
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helmfile-1.7.2/docs/requirements.txt 
new/helmfile-1.7.3/docs/requirements.txt
--- old/helmfile-1.7.2/docs/requirements.txt    2026-07-31 16:22:31.000000000 
+0200
+++ new/helmfile-1.7.3/docs/requirements.txt    2026-08-04 12:31:11.000000000 
+0200
@@ -2,7 +2,7 @@
 click==8.1.2
 ghp-import==2.0.2
 gitdb==4.0.9
-GitPython==3.1.54
+GitPython==3.1.57
 importlib-metadata==4.11.3
 Jinja2==3.1.6
 Markdown==3.8.1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helmfile-1.7.2/go.mod new/helmfile-1.7.3/go.mod
--- old/helmfile-1.7.2/go.mod   2026-07-31 16:22:31.000000000 +0200
+++ new/helmfile-1.7.3/go.mod   2026-08-04 12:31:11.000000000 +0200
@@ -6,8 +6,8 @@
        dario.cat/mergo v1.0.2
        github.com/Masterminds/semver/v3 v3.5.0
        github.com/Masterminds/sprig/v3 v3.3.0
-       github.com/aws/aws-sdk-go-v2/config v1.32.31
-       github.com/aws/aws-sdk-go-v2/service/s3 v1.106.2
+       github.com/aws/aws-sdk-go-v2/config v1.32.34
+       github.com/aws/aws-sdk-go-v2/service/s3 v1.106.3
        github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
        github.com/go-test/deep v1.1.1
        github.com/gofrs/flock v0.13.0
@@ -18,7 +18,7 @@
        github.com/hashicorp/go-cty-funcs v0.1.0
        github.com/hashicorp/go-getter/v2 v2.2.3
        github.com/hashicorp/hcl/v2 v2.24.0
-       github.com/helmfile/chartify v0.28.0
+       github.com/helmfile/chartify v0.28.1
        github.com/helmfile/vals v0.45.0
        github.com/sashabaranov/go-openai v1.41.2
        github.com/spf13/cobra v1.10.2
@@ -166,26 +166,26 @@
        github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // 
indirect
        github.com/atotto/clipboard v0.1.4 // indirect
        github.com/avelino/slugify v0.0.0-20180501145920-855f152bd774 // 
indirect
-       github.com/aws/aws-sdk-go-v2 v1.43.2 // indirect
-       github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.15 // 
indirect
-       github.com/aws/aws-sdk-go-v2/credentials v1.19.30 // indirect
-       github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.31 // indirect
+       github.com/aws/aws-sdk-go-v2 v1.43.3 // indirect
+       github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.16 // 
indirect
+       github.com/aws/aws-sdk-go-v2/credentials v1.19.33 // indirect
+       github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.34 // indirect
        github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.22.28 // indirect
-       github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.33 // indirect
-       github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.33 // indirect
-       github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.34 // indirect
-       github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.14 
// indirect
-       github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.26 // 
indirect
-       github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.33 // 
indirect
-       github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.34 // 
indirect
+       github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.34 // indirect
+       github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.34 // indirect
+       github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.35 // indirect
+       github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.15 
// indirect
+       github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.27 // 
indirect
+       github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.34 // 
indirect
+       github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.35 // 
indirect
        github.com/aws/aws-sdk-go-v2/service/kms v1.54.1 // indirect
        github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.43.1 // indirect
-       github.com/aws/aws-sdk-go-v2/service/signin v1.5.0 // indirect
+       github.com/aws/aws-sdk-go-v2/service/signin v1.5.3 // indirect
        github.com/aws/aws-sdk-go-v2/service/ssm v1.72.0 // indirect
-       github.com/aws/aws-sdk-go-v2/service/sso v1.33.0 // indirect
-       github.com/aws/aws-sdk-go-v2/service/ssooidc v1.38.0 // indirect
-       github.com/aws/aws-sdk-go-v2/service/sts v1.45.0 // indirect
-       github.com/aws/smithy-go v1.27.5 // indirect
+       github.com/aws/aws-sdk-go-v2/service/sso v1.33.3 // indirect
+       github.com/aws/aws-sdk-go-v2/service/ssooidc v1.38.3 // indirect
+       github.com/aws/aws-sdk-go-v2/service/sts v1.45.3 // indirect
+       github.com/aws/smithy-go v1.27.6 // indirect
        github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
        github.com/blang/semver/v4 v4.0.0 // indirect
        github.com/cenkalti/backoff/v4 v4.3.0 // indirect
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helmfile-1.7.2/go.sum new/helmfile-1.7.3/go.sum
--- old/helmfile-1.7.2/go.sum   2026-07-31 16:22:31.000000000 +0200
+++ new/helmfile-1.7.3/go.sum   2026-08-04 12:31:11.000000000 +0200
@@ -154,50 +154,50 @@
 github.com/avelino/slugify v0.0.0-20180501145920-855f152bd774/go.mod 
h1:5wi5YYOpfuAKwL5XLFYopbgIl/v7NZxaJpa/4X6yFKE=
 github.com/aws/aws-sdk-go v1.55.8 
h1:JRmEUbU52aJQZ2AjX4q4Wu7t4uZjOu71uyNmaWlUkJQ=
 github.com/aws/aws-sdk-go v1.55.8/go.mod 
h1:ZkViS9AqA6otK+JBBNH2++sx1sgxrPKcSzPPvQkUtXk=
-github.com/aws/aws-sdk-go-v2 v1.43.2 
h1:cl+IXwWb3qazClUcm08tGSsB6OiuV83JVJO9B0jQcPc=
-github.com/aws/aws-sdk-go-v2 v1.43.2/go.mod 
h1:WEzLKBh/mEjXvx1FtQMWgSxMSTVqxQzjkRtk5fa3wkg=
-github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.15 
h1:rq/p1VNFfygoKEQ9hHMKsKBE98lspPvT8IxaFs5mFhw=
-github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.15/go.mod 
h1:bELIhlPfW8OkpDhP1MvCjHDtvv8NhiBTz+K4o26zrXA=
-github.com/aws/aws-sdk-go-v2/config v1.32.31 
h1:n4nY9O3QKoHIkL85EX+V8RcMFtOhlpTFhGArg915PXk=
-github.com/aws/aws-sdk-go-v2/config v1.32.31/go.mod 
h1:PN0NYDCCoOpGGsZ2+elDUidmHfQBPyYzN2GCgl8HEBs=
-github.com/aws/aws-sdk-go-v2/credentials v1.19.30 
h1:TTCvvzFU6gXa4iJecNG/0F/B0oYTiazoRECr2XyLHrY=
-github.com/aws/aws-sdk-go-v2/credentials v1.19.30/go.mod 
h1:jKxAp2AEncnliinzpgOSZDFv6+VjvWhjw/AtbfsWT9U=
-github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.31 
h1:kfVL5wAunCJycL6MOQ6aNh6PlAYEymflcjuKmrWUA0o=
-github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.31/go.mod 
h1:nWfRNDAppujCQgOUd43lKT4yeLv9z3nJ3bw1G3BgQKo=
+github.com/aws/aws-sdk-go-v2 v1.43.3 
h1:XJIcfv8uDs2ukdQsoAC8/Ebu1ejxwzlayl2ZsiFns2A=
+github.com/aws/aws-sdk-go-v2 v1.43.3/go.mod 
h1:70vwSy16txshwG+g55WkpgPKDIByzHI8ccBsOteo3bQ=
+github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.16 
h1:aiuaKlDweRC5qExJondpWjOgyzMHpofpwspGXUtwn4c=
+github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.16/go.mod 
h1:nG/LOlmox9BDe9HvQnXWzgcK8uKbgBMZ/Hp5pVt/21I=
+github.com/aws/aws-sdk-go-v2/config v1.32.34 
h1:o+YAizrX562nEZXaB38uYTK8RvIsvW0uuRP+e5e0Pfk=
+github.com/aws/aws-sdk-go-v2/config v1.32.34/go.mod 
h1:wc0zYRChOniiufvdWiRVf3jgXSgbkvaD683IHHHc2ZQ=
+github.com/aws/aws-sdk-go-v2/credentials v1.19.33 
h1:/e5V3EWfeDiW6cuRxHsC8gbwko4/vvVYPJR2afBKFFY=
+github.com/aws/aws-sdk-go-v2/credentials v1.19.33/go.mod 
h1:ZxAmkcyOM9beY/WO9oxp2oVPXiP3rq5N1/p4NbenJdE=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.34 
h1:1EsGke6rTD2CG3j2MMVB77n6Q+FlbQWYI/dFdLWBNtM=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.34/go.mod 
h1:5B1Z/QbaWzqoWRzYxZfmCbDDRcvUHcfAIQw/S+KfDmc=
 github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.22.28 
h1:ez4y5o7sa0uaRI8BquYOXtZpioUPhbQEh7Igm88oV9U=
 github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.22.28/go.mod 
h1:TpmZOrQA12XKEpVypgBGZSQBsm1WUTndCiSnbDsbvug=
-github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.33 
h1:HAp1wLFZzch054uh3FK7rcVYg4v7J2FxVf3h3IGNZas=
-github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.33/go.mod 
h1:mJk5fmqnF+WUlMdPG37pR2Fh3oh6r8F6ZGUgPKvzu0c=
-github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.33 
h1:0YA0aCKgsJyno6xkFfaIgjE3/wK08+Qxo9nQfe1UrWM=
-github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.33/go.mod 
h1:UZqj4WIdTH+ga8Y/DgpAuy/8cGjM3h7gDCliJYGg2SE=
-github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.34 
h1:HQYnjFnXpX8EbPW5M1QT8mXzesRPwly0HEPTcFlS02Y=
-github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.34/go.mod 
h1:tGzj56niKYZBbDIRhwPGDqrULzmWv5b6uBQGqyNaFZw=
-github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.14 
h1:SA43nfaY7+1jjMNIc2ywu99JLJLButtIdLP6j+bT870=
-github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.14/go.mod 
h1:Du3llKcwbQvHsTXSLzTOGQz0DTDBMEzdg7DAGu7inrY=
-github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.26 
h1:Eflerh7atY6HN0yz60peNLOkJA2ZKUyYjZexMbqwMCE=
-github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.26/go.mod 
h1:dCAXNDmik9NuTjfsvCvW22S6ZFpxmtoliFoQu5XFkh8=
-github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.33 
h1:mqI7OrxN/DUH85F5OqVn3cIfuZ3+HVcebUm2N8mLlgQ=
-github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.33/go.mod 
h1:eZ5jdEpvaaOU8nWWE4cTAJETSEA5FZoWxvNRao4piHY=
-github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.34 
h1:Lercr2QB2rOrCwyOusmnQ7IiopfkGcZAgMJbjcSdK/s=
-github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.34/go.mod 
h1:W0xXPPCb2HAqa3cp2f/nRvE+jGgBmchiuXrfBRlfb1I=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.34 
h1:vuIfjzoeqhQMGJyOBU3t0ZEjn2jrN8Bbg1N4CgjzM5Q=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.34/go.mod 
h1:hP28cN4CPJLZHirdQPrZR50JcLN4ApRJP2tzG8cRlhY=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.34 
h1:9faHsnqxJ1vDvB4wMZy/ajIDyz5QhllQjjc72RJpXAw=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.34/go.mod 
h1:Yp6nIyejpa23nzlB/LhT63KTla9Jdi06nv/HH/OkAH8=
+github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.35 
h1:Oe8gMKJLO5awqpa5EhAGKVnBv1s+brdWVuxM2mDa7zA=
+github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.35/go.mod 
h1:FZevcG9cOST/FWAAUhHIchjR9fXFXFRCWodOhx+PDLA=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.15 
h1:JJLBQxwY+AFwuPAi5ivGc1ChnTdUt4cXMv7e76m2c/Y=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.15/go.mod 
h1:lQknBIe78MVL0cQOQDlag8KGflMbMEVFx9mB6O8ENvk=
+github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.27 
h1:zwB6ltUc0UiyOsRQaMQ8jNLjKECbjhadCyl4hqV0y/c=
+github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.27/go.mod 
h1:ce9y+Y+hGLUyPKJZZJGoFLuFJNfCNuWZTujUJAsckQA=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.34 
h1:sYg4qHWLqsjp15PzX7XCOHSOgKEGoZ5vQY43VvZ1pas=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.34/go.mod 
h1:N58SSz3roKf1HzW5qRaOiyk6MbDLTKgLPvlTfJ90iyI=
+github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.35 
h1:ohfdSAm4TA6nryIY7mLqe4mnSIAnAreoAPBM81ZVoIM=
+github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.35/go.mod 
h1:uUjphnxMb3HH3vIiOHl4dH0fGNKL+csjqRQEabbfw5k=
 github.com/aws/aws-sdk-go-v2/service/kms v1.54.1 
h1:aeJAJyvWS3gQ679pJbz8ZdOh3MViD1zvEdoZMVEawbg=
 github.com/aws/aws-sdk-go-v2/service/kms v1.54.1/go.mod 
h1:0RXNc6Yf3AvSMldGD6Lcch96Ojlw2TtGnHsqfD/L4u8=
-github.com/aws/aws-sdk-go-v2/service/s3 v1.106.2 
h1:lFSYDEyC1JHucMH3fdczMTnDaghqNttyRXKM8JY9EJQ=
-github.com/aws/aws-sdk-go-v2/service/s3 v1.106.2/go.mod 
h1:aw1E7RCjxs5Sd8N6WdICMcMroff12Tzxte+ELXXNqRU=
+github.com/aws/aws-sdk-go-v2/service/s3 v1.106.3 
h1:oSfubHEP3a0nTRAtm99IDaws0f15qwf+fOwS1Esh5jI=
+github.com/aws/aws-sdk-go-v2/service/s3 v1.106.3/go.mod 
h1:lWk6L5Q3YkaC7so1bQUJkvF7hj2KUFzdZ4w15wc2GHY=
 github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.43.1 
h1:ZI18/nuaDBwwMJ95paJrb4NT2TbqEvptj/rlMkEO7DI=
 github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.43.1/go.mod 
h1:oUyL28WfxY0RqPhFpkrWZx26Cu4JlyrWMMcWq8qqhi0=
-github.com/aws/aws-sdk-go-v2/service/signin v1.5.0 
h1:OHH5iTQvVGmfHjX/5Q+vFuA/Rf2x6/95aJ/75QCQSm4=
-github.com/aws/aws-sdk-go-v2/service/signin v1.5.0/go.mod 
h1:mCF3AK9PpL49oOrhniUXWAfhVBVQ/XbytoE5eccZUIs=
+github.com/aws/aws-sdk-go-v2/service/signin v1.5.3 
h1:togAtAmgV5IGMnQDuBDJeM8z5Y5RN6G7xeOgphWz+Yc=
+github.com/aws/aws-sdk-go-v2/service/signin v1.5.3/go.mod 
h1:T7xKUUUvN7W3RW8UmMvKnD12xqh+Ux2gCPHPhnt64Dg=
 github.com/aws/aws-sdk-go-v2/service/ssm v1.72.0 
h1:jl+7QcR+PEJVQXK1W5NSXw9EKd+w7Cu4Pwj/WvUIHb0=
 github.com/aws/aws-sdk-go-v2/service/ssm v1.72.0/go.mod 
h1:xabzRvdbMs3FG9kU5M6RUOuCW6wXDkpdIqoXXNzA1nQ=
-github.com/aws/aws-sdk-go-v2/service/sso v1.33.0 
h1:CaJyYhxBE0M/HJX/YvSaSmQlsI91VHB0lKU8LtLxL3A=
-github.com/aws/aws-sdk-go-v2/service/sso v1.33.0/go.mod 
h1:+e6BMRMPjBQoCw/WovYR9GLy2IU0z4Q77smOB1DraSg=
-github.com/aws/aws-sdk-go-v2/service/ssooidc v1.38.0 
h1:tC323YV77QdafeBr6LUhLDTsboyuyHLNRwAyCP44kGU=
-github.com/aws/aws-sdk-go-v2/service/ssooidc v1.38.0/go.mod 
h1:SfLK1sgviHmbI+MozR9iDwDjL4cdCVZtahsjoR+z7wg=
-github.com/aws/aws-sdk-go-v2/service/sts v1.45.0 
h1:Pd6PNlp4t8PTXxqzstICl52Wsy78vpjFZ7PRUj44mJc=
-github.com/aws/aws-sdk-go-v2/service/sts v1.45.0/go.mod 
h1:rmQ0TnHzuLPmabgjPcsywhsSOmaBDgzR4zvDxSPsGdg=
-github.com/aws/smithy-go v1.27.5 
h1:d1ro7KpYOYwP6m73YFa+Kc/A130VsAdX68SpsJwARMM=
-github.com/aws/smithy-go v1.27.5/go.mod 
h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
+github.com/aws/aws-sdk-go-v2/service/sso v1.33.3 
h1:YjH64OUytnWZBHUtM9GMyi4ZWBiSQdEJkZuPykOIe44=
+github.com/aws/aws-sdk-go-v2/service/sso v1.33.3/go.mod 
h1:5qoHcDZDTSJotoKk1bvVRPv1MXaL/NhfY9ng8D1g/ig=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.38.3 
h1:A4o1di/XGaqtw6r3toSBrFX2U7mVSLqg7jo9wL4I+cU=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.38.3/go.mod 
h1:sKuKz2kHtrGVtFu34vbM3LWSA9CKD9YZUmm6e5PPqRA=
+github.com/aws/aws-sdk-go-v2/service/sts v1.45.3 
h1:Fi7+DiKN1+QphlajvE6FqeZ8GRbnnRul7zTdUiRpbGc=
+github.com/aws/aws-sdk-go-v2/service/sts v1.45.3/go.mod 
h1:KCc3e27fHZUGtzpek7wZcp6dyCpGkJJo/+3PBujh/yU=
+github.com/aws/smithy-go v1.27.6 
h1:0zjT8jgK3jbrTT7JJ3EE6JsMhX8JTrZ+f1sEndYDXrA=
+github.com/aws/smithy-go v1.27.6/go.mod 
h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
 github.com/aymanbagabas/go-osc52/v2 v2.0.1 
h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
 github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod 
h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
 github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
@@ -536,8 +536,8 @@
 github.com/hashicorp/jsonapi v1.4.3-0.20250220162346-81a76b606f3e/go.mod 
h1:kWfdn49yCjQvbpnvY1dxxAuAFzISwrrMDQOcu6NsFoM=
 github.com/hashicorp/vault/api v1.23.0 
h1:gXgluBsSECfRWTSW9niY2jwg2e9mMJc4WoHNv4g3h6A=
 github.com/hashicorp/vault/api v1.23.0/go.mod 
h1:zransKiB9ftp+kgY8ydjnvCU7Wk8i9L0DYWpXeMj9ko=
-github.com/helmfile/chartify v0.28.0 
h1:AK04JykpFXQAtIbEN2DwAZsoSNdDZdAGY5W5FIoK8bk=
-github.com/helmfile/chartify v0.28.0/go.mod 
h1:LKUELzZ2TaaCAD4EAFbaCkmRXNnt4uWlJts7GBdFVAQ=
+github.com/helmfile/chartify v0.28.1 
h1:dv7XfWT+OYtqSQ3f4SqXwUk6FyTuS6aH1M3+eF4DkLc=
+github.com/helmfile/chartify v0.28.1/go.mod 
h1:LKUELzZ2TaaCAD4EAFbaCkmRXNnt4uWlJts7GBdFVAQ=
 github.com/helmfile/vals v0.45.0 
h1:j5e9enLhBfaiYKKPJWEFAzW0DQJlVXyvnKPWWP3gdJg=
 github.com/helmfile/vals v0.45.0/go.mod 
h1:dJ5VGNN0cbusJoAFFINFeimbLV19hhtJJ1328ZFLJzA=
 github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec 
h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog=
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helmfile-1.7.2/pkg/app/app.go 
new/helmfile-1.7.3/pkg/app/app.go
--- old/helmfile-1.7.2/pkg/app/app.go   2026-07-31 16:22:31.000000000 +0200
+++ new/helmfile-1.7.3/pkg/app/app.go   2026-08-04 12:31:11.000000000 +0200
@@ -1834,24 +1834,25 @@
        detectedKubeVersion := a.detectKubeVersion(st)
 
        diffOpts := &state.DiffOpts{
-               Color:                   c.Color(),
-               NoColor:                 c.NoColor(),
-               Context:                 c.Context(),
-               Output:                  c.DiffOutput(),
-               Set:                     c.Set(),
-               SkipCleanup:             c.SkipCleanup(),
-               SkipDiffOnInstall:       c.SkipDiffOnInstall(),
-               ReuseValues:             c.ReuseValues(),
-               ResetValues:             c.ResetValues(),
-               DiffArgs:                c.DiffArgs(),
-               TemplateArgs:            c.TemplateArgs(),
-               PostRenderer:            c.PostRenderer(),
-               PostRendererArgs:        c.PostRendererArgs(),
-               SkipSchemaValidation:    c.SkipSchemaValidation(),
-               SuppressOutputLineRegex: c.SuppressOutputLineRegex(),
-               TakeOwnership:           c.TakeOwnership(),
-               ServerSide:              c.ServerSide(),
-               DetectedKubeVersion:     detectedKubeVersion,
+               Color:                       c.Color(),
+               NoColor:                     c.NoColor(),
+               Context:                     c.Context(),
+               Output:                      c.DiffOutput(),
+               Set:                         c.Set(),
+               SkipCleanup:                 c.SkipCleanup(),
+               SkipDiffOnInstall:           c.SkipDiffOnInstall(),
+               SkipDiffValidationOnInstall: c.SkipDiffValidationOnInstall(),
+               ReuseValues:                 c.ReuseValues(),
+               ResetValues:                 c.ResetValues(),
+               DiffArgs:                    c.DiffArgs(),
+               TemplateArgs:                c.TemplateArgs(),
+               PostRenderer:                c.PostRenderer(),
+               PostRendererArgs:            c.PostRendererArgs(),
+               SkipSchemaValidation:        c.SkipSchemaValidation(),
+               SuppressOutputLineRegex:     c.SuppressOutputLineRegex(),
+               TakeOwnership:               c.TakeOwnership(),
+               ServerSide:                  c.ServerSide(),
+               DetectedKubeVersion:         detectedKubeVersion,
        }
 
        infoMsg, releasesToUpdate, releasesToDelete, diffErrs := r.diff(false, 
detailedExitCode, c, diffOpts)
@@ -2122,23 +2123,24 @@
                detectedKubeVersion := a.detectKubeVersion(st)
 
                opts := &state.DiffOpts{
-                       Context:                 c.Context(),
-                       Output:                  c.DiffOutput(),
-                       Color:                   c.Color(),
-                       NoColor:                 c.NoColor(),
-                       Set:                     c.Set(),
-                       DiffArgs:                c.DiffArgs(),
-                       TemplateArgs:            c.TemplateArgs(),
-                       SkipDiffOnInstall:       c.SkipDiffOnInstall(),
-                       ReuseValues:             c.ReuseValues(),
-                       ResetValues:             c.ResetValues(),
-                       PostRenderer:            c.PostRenderer(),
-                       PostRendererArgs:        c.PostRendererArgs(),
-                       SkipSchemaValidation:    c.SkipSchemaValidation(),
-                       SuppressOutputLineRegex: c.SuppressOutputLineRegex(),
-                       TakeOwnership:           c.TakeOwnership(),
-                       ServerSide:              c.ServerSide(),
-                       DetectedKubeVersion:     detectedKubeVersion,
+                       Context:                     c.Context(),
+                       Output:                      c.DiffOutput(),
+                       Color:                       c.Color(),
+                       NoColor:                     c.NoColor(),
+                       Set:                         c.Set(),
+                       DiffArgs:                    c.DiffArgs(),
+                       TemplateArgs:                c.TemplateArgs(),
+                       SkipDiffOnInstall:           c.SkipDiffOnInstall(),
+                       SkipDiffValidationOnInstall: 
c.SkipDiffValidationOnInstall(),
+                       ReuseValues:                 c.ReuseValues(),
+                       ResetValues:                 c.ResetValues(),
+                       PostRenderer:                c.PostRenderer(),
+                       PostRendererArgs:            c.PostRendererArgs(),
+                       SkipSchemaValidation:        c.SkipSchemaValidation(),
+                       SuppressOutputLineRegex:     
c.SuppressOutputLineRegex(),
+                       TakeOwnership:               c.TakeOwnership(),
+                       ServerSide:                  c.ServerSide(),
+                       DetectedKubeVersion:         detectedKubeVersion,
                }
 
                filtered := &Run{
@@ -2363,23 +2365,24 @@
                if diffC, ok := c.(DiffConfigProvider); ok {
                        detectedKubeVersion := a.detectKubeVersion(st)
                        diffOpts := &state.DiffOpts{
-                               Context:                 diffC.Context(),
-                               Output:                  diffC.DiffOutput(),
-                               Color:                   diffC.Color(),
-                               NoColor:                 diffC.NoColor(),
-                               Set:                     diffC.Set(),
-                               DiffArgs:                diffC.DiffArgs(),
-                               TemplateArgs:            diffC.TemplateArgs(),
-                               SkipDiffOnInstall:       
diffC.SkipDiffOnInstall(),
-                               ReuseValues:             diffC.ReuseValues(),
-                               ResetValues:             diffC.ResetValues(),
-                               PostRenderer:            diffC.PostRenderer(),
-                               PostRendererArgs:        
diffC.PostRendererArgs(),
-                               SkipSchemaValidation:    
diffC.SkipSchemaValidation(),
-                               SuppressOutputLineRegex: 
diffC.SuppressOutputLineRegex(),
-                               TakeOwnership:           diffC.TakeOwnership(),
-                               ServerSide:              diffC.ServerSide(),
-                               DetectedKubeVersion:     detectedKubeVersion,
+                               Context:                     diffC.Context(),
+                               Output:                      diffC.DiffOutput(),
+                               Color:                       diffC.Color(),
+                               NoColor:                     diffC.NoColor(),
+                               Set:                         diffC.Set(),
+                               DiffArgs:                    diffC.DiffArgs(),
+                               TemplateArgs:                
diffC.TemplateArgs(),
+                               SkipDiffOnInstall:           
diffC.SkipDiffOnInstall(),
+                               SkipDiffValidationOnInstall: 
diffC.SkipDiffValidationOnInstall(),
+                               ReuseValues:                 
diffC.ReuseValues(),
+                               ResetValues:                 
diffC.ResetValues(),
+                               PostRenderer:                
diffC.PostRenderer(),
+                               PostRendererArgs:            
diffC.PostRendererArgs(),
+                               SkipSchemaValidation:        
diffC.SkipSchemaValidation(),
+                               SuppressOutputLineRegex:     
diffC.SuppressOutputLineRegex(),
+                               TakeOwnership:               
diffC.TakeOwnership(),
+                               ServerSide:                  diffC.ServerSide(),
+                               DetectedKubeVersion:         
detectedKubeVersion,
                        }
                        infoMsgPtr, _, _, diffErrs := r.diff(false, 
diffC.DetailedExitcode(), diffC, diffOpts)
                        if len(diffErrs) > 0 {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helmfile-1.7.2/pkg/app/app_test.go 
new/helmfile-1.7.3/pkg/app/app_test.go
--- old/helmfile-1.7.2/pkg/app/app_test.go      2026-07-31 16:22:31.000000000 
+0200
+++ new/helmfile-1.7.3/pkg/app/app_test.go      2026-08-04 12:31:11.000000000 
+0200
@@ -2697,6 +2697,10 @@
        return a.skipDiffOnInstall
 }
 
+func (a applyConfig) SkipDiffValidationOnInstall() bool {
+       return false
+}
+
 func (a applyConfig) SyncArgs() string {
        return a.syncArgs
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helmfile-1.7.2/pkg/app/config.go 
new/helmfile-1.7.3/pkg/app/config.go
--- old/helmfile-1.7.2/pkg/app/config.go        2026-07-31 16:22:31.000000000 
+0200
+++ new/helmfile-1.7.3/pkg/app/config.go        2026-08-04 12:31:11.000000000 
+0200
@@ -86,6 +86,7 @@
        Validate() bool
        SkipCleanup() bool
        SkipDiffOnInstall() bool
+       SkipDiffValidationOnInstall() bool
 
        DiffArgs() string
        SyncArgs() string
@@ -182,6 +183,7 @@
        NoHooks() bool
        SuppressDiff() bool
        SkipDiffOnInstall() bool
+       SkipDiffValidationOnInstall() bool
        DiffArgs() string
        TemplateArgs() string
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helmfile-1.7.2/pkg/app/diff_test.go 
new/helmfile-1.7.3/pkg/app/diff_test.go
--- old/helmfile-1.7.2/pkg/app/diff_test.go     2026-07-31 16:22:31.000000000 
+0200
+++ new/helmfile-1.7.3/pkg/app/diff_test.go     2026-08-04 12:31:11.000000000 
+0200
@@ -159,6 +159,10 @@
        return a.skipDiffOnInstall
 }
 
+func (a diffConfig) SkipDiffValidationOnInstall() bool {
+       return false
+}
+
 func (a diffConfig) Logger() *zap.SugaredLogger {
        return a.logger
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helmfile-1.7.2/pkg/app/init.go 
new/helmfile-1.7.3/pkg/app/init.go
--- old/helmfile-1.7.2/pkg/app/init.go  2026-07-31 16:22:31.000000000 +0200
+++ new/helmfile-1.7.3/pkg/app/init.go  2026-08-04 12:31:11.000000000 +0200
@@ -19,7 +19,7 @@
 
 const (
        HelmRequiredVersion            = "v3.18.6" // Minimum required version 
(supports Helm 3.x and 4.x)
-       HelmDiffRecommendedVersion     = "v3.15.10"
+       HelmDiffRecommendedVersion     = "v3.15.11"
        HelmRecommendedVersion         = "v4.2.3" // Recommended Helm 4 version
        HelmSecretsRecommendedVersion  = "v4.7.4" // v4.7.0+ works with both 
Helm 3 (single plugin) and Helm 4 (split plugin architecture)
        HelmGitRecommendedVersion      = "v1.3.0"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helmfile-1.7.2/pkg/app/init_test.go 
new/helmfile-1.7.3/pkg/app/init_test.go
--- old/helmfile-1.7.2/pkg/app/init_test.go     2026-07-31 16:22:31.000000000 
+0200
+++ new/helmfile-1.7.3/pkg/app/init_test.go     2026-08-04 12:31:11.000000000 
+0200
@@ -209,7 +209,7 @@
        assert.Contains(t, err.Error(), "sh: not found")
 }
 
-func TestCheckHelmPlugins_UpdateFailsFallbackToReinstall(t *testing.T) {
+func TestCheckHelmPlugins_UpdateUsesUninstallReinstall(t *testing.T) {
        pluginsDir := t.TempDir()
        t.Setenv("HELM_PLUGINS", pluginsDir)
 
@@ -221,9 +221,11 @@
        // Track which plugin sub-commands were executed.
        var calledOps []string
 
-       // The mock runner simulates "helm plugin update" failing and falling 
back to
-       // "helm plugin uninstall" + "helm plugin install" which succeeds and 
writes the
-       // required version to disk.
+       // UpdatePlugin updates a plugin by uninstalling the stale version and 
reinstalling
+       // the exact pinned version (helm "plugin update" is intentionally NOT 
used because
+       // it does not honor --version and silently leaves the old version 
installed; see
+       // issues #2726 and #2548). This mock simulates a successful uninstall 
+ install
+       // that writes the required version to disk.
        runner := &initMockRunner{
                executeFunc: func(cmd string, args []string, env 
map[string]string, enableLiveOutput bool) ([]byte, error) {
                        for _, a := range args {
@@ -234,11 +236,13 @@
                        if len(args) >= 2 && args[0] == "plugin" {
                                switch args[1] {
                                case "update":
+                                       // UpdatePlugin must never invoke `helm 
plugin update` (it does not honor
+                                       // --version and silently leaves the 
old version installed; see #2726).
+                                       // Record the call so the NotContains 
assertion below can catch a regression.
                                        if len(args) >= 3 {
                                                calledOps = append(calledOps, 
"update:"+args[2])
                                        }
-                                       // Simulate helm plugin update failing 
(as can happen with Helm 4)
-                                       return nil, helmexec.ExitError{Message: 
"plugin update failed", Code: 1}
+                                       return nil, helmexec.ExitError{Message: 
"plugin update must not be used", Code: 1}
                                case "uninstall":
                                        if len(args) >= 3 {
                                                calledOps = append(calledOps, 
"uninstall:"+args[2])
@@ -266,13 +270,13 @@
 
        h := NewHelmfileInit("helm", &mockInitConfigProvider{force: true}, 
newTestLogger(), runner)
        err := h.CheckHelmPlugins()
-       // Should succeed: update failed but fallback reinstall updated the 
plugin
+       // Should succeed: uninstall + reinstall updated each plugin to the 
pinned version
        assert.NoError(t, err)
 
-       // Verify that for each plugin the fallback path was taken:
-       // update was attempted, then uninstall + install were called.
+       // Verify that for each plugin the reliable update path was taken:
+       // the unreliable "plugin update" is never called; only uninstall + 
install are.
        for _, p := range helmPlugins {
-               assert.Contains(t, calledOps, "update:"+p.name, "expected 
update to be attempted for plugin %s", p.name)
+               assert.NotContains(t, calledOps, "update:"+p.name, "'plugin 
update' must not be used for plugin %s", p.name)
                assert.Contains(t, calledOps, "uninstall:"+p.name, "expected 
uninstall to be called for plugin %s", p.name)
                assert.Contains(t, calledOps, "install:"+p.name, "expected 
install to be called for plugin %s", p.name)
        }
@@ -298,9 +302,8 @@
        }
 
        // The mock runner simulates:
-       // 1. "helm plugin update" failing
-       // 2. "helm plugin uninstall" succeeding
-       // 3. "helm plugin install" writing the correct version but returning 
an error
+       // 1. "helm plugin uninstall" succeeding
+       // 2. "helm plugin install" writing the correct version but returning 
an error
        //    (e.g., post-install script error on Windows)
        // In this case, UpdatePlugin returns the install error, but 
CheckHelmPlugins
        // verifies the version and warns instead of returning an error.
@@ -313,8 +316,6 @@
                        }
                        if len(args) >= 2 && args[0] == "plugin" {
                                switch args[1] {
-                               case "update":
-                                       return nil, helmexec.ExitError{Message: 
"plugin update failed", Code: 1}
                                case "uninstall":
                                        return []byte{}, nil
                                case "install":
@@ -338,7 +339,7 @@
 
        h := NewHelmfileInit("helm", &mockInitConfigProvider{force: true}, 
newTestLogger(), runner)
        err := h.CheckHelmPlugins()
-       // Should succeed: UpdatePlugin returned an error (from the fallback 
install step),
+       // Should succeed: UpdatePlugin returned an error (from the reinstall 
step),
        // but the plugin is present at the required version, so 
CheckHelmPlugins warns and continues.
        assert.NoError(t, err)
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helmfile-1.7.2/pkg/config/apply.go 
new/helmfile-1.7.3/pkg/config/apply.go
--- old/helmfile-1.7.2/pkg/config/apply.go      2026-07-31 16:22:31.000000000 
+0200
+++ new/helmfile-1.7.3/pkg/config/apply.go      2026-08-04 12:31:11.000000000 
+0200
@@ -37,6 +37,8 @@
        EnforceNeedsAreInstalled bool
        // SkipDiffOnInstall is true if the diff should be skipped on install
        SkipDiffOnInstall bool
+       // SkipDiffValidationOnInstall disables K8s API validation when running 
helm-diff on a release being newly installed
+       SkipDiffValidationOnInstall bool
        // DiffArgs is the list of arguments to pass to the helm-diff.
        DiffArgs string
        // IncludeTests is true if the tests should be included
@@ -199,6 +201,11 @@
        return a.ApplyOptions.SkipDiffOnInstall
 }
 
+// SkipDiffValidationOnInstall returns the skip diff validation on install.
+func (a *ApplyImpl) SkipDiffValidationOnInstall() bool {
+       return a.ApplyOptions.SkipDiffValidationOnInstall
+}
+
 // DiffArgs is the list of arguments to pass to helm-diff.
 func (a *ApplyImpl) DiffArgs() string {
        return a.ApplyOptions.DiffArgs
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helmfile-1.7.2/pkg/config/diff.go 
new/helmfile-1.7.3/pkg/config/diff.go
--- old/helmfile-1.7.2/pkg/config/diff.go       2026-07-31 16:22:31.000000000 
+0200
+++ new/helmfile-1.7.3/pkg/config/diff.go       2026-08-04 12:31:11.000000000 
+0200
@@ -22,6 +22,8 @@
        EnforceNeedsAreInstalled bool
        // SkipDiffOnInstall is the skip diff on install flag
        SkipDiffOnInstall bool
+       // SkipDiffValidationOnInstall disables K8s API validation when running 
helm-diff on a release being newly installed
+       SkipDiffValidationOnInstall bool
        // ShowSecrets is the show secrets flag
        ShowSecrets bool
        // NoHooks skips hooks during diff
@@ -168,6 +170,11 @@
        return t.DiffOptions.SkipDiffOnInstall
 }
 
+// SkipDiffValidationOnInstall returns the skip diff validation on install
+func (t *DiffImpl) SkipDiffValidationOnInstall() bool {
+       return t.DiffOptions.SkipDiffValidationOnInstall
+}
+
 // DiffArgs returns the list of arguments to pass to helm-diff.
 func (t *DiffImpl) DiffArgs() string {
        return t.DiffOptions.DiffArgs
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helmfile-1.7.2/pkg/config/sync.go 
new/helmfile-1.7.3/pkg/config/sync.go
--- old/helmfile-1.7.2/pkg/config/sync.go       2026-07-31 16:22:31.000000000 
+0200
+++ new/helmfile-1.7.3/pkg/config/sync.go       2026-08-04 12:31:11.000000000 
+0200
@@ -75,19 +75,20 @@
        TemplateArgs string
 
        // Diff-related options for --interactive mode
-       SuppressOutputLineRegex []string
-       IncludeTests            bool
-       Suppress                []string
-       SuppressSecrets         bool
-       ShowSecrets             bool
-       NoHooks                 bool
-       SuppressDiff            bool
-       SkipDiffOnInstall       bool
-       DiffArgs                string
-       DetailedExitcode        bool
-       StripTrailingCR         bool
-       Context                 int
-       DiffOutput              string
+       SuppressOutputLineRegex     []string
+       IncludeTests                bool
+       Suppress                    []string
+       SuppressSecrets             bool
+       ShowSecrets                 bool
+       NoHooks                     bool
+       SuppressDiff                bool
+       SkipDiffOnInstall           bool
+       SkipDiffValidationOnInstall bool
+       DiffArgs                    string
+       DetailedExitcode            bool
+       StripTrailingCR             bool
+       Context                     int
+       DiffOutput                  string
 }
 
 // NewSyncOptions creates a new Apply
@@ -308,6 +309,11 @@
        return t.SyncOptions.SkipDiffOnInstall
 }
 
+// SkipDiffValidationOnInstall returns the SkipDiffValidationOnInstall.
+func (t *SyncImpl) SkipDiffValidationOnInstall() bool {
+       return t.SyncOptions.SkipDiffValidationOnInstall
+}
+
 // DiffArgs returns the DiffArgs.
 func (t *SyncImpl) DiffArgs() string {
        return t.SyncOptions.DiffArgs
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helmfile-1.7.2/pkg/helmexec/exec.go 
new/helmfile-1.7.3/pkg/helmexec/exec.go
--- old/helmfile-1.7.2/pkg/helmexec/exec.go     2026-07-31 16:22:31.000000000 
+0200
+++ new/helmfile-1.7.3/pkg/helmexec/exec.go     2026-08-04 12:31:11.000000000 
+0200
@@ -10,6 +10,7 @@
        "os"
        "path/filepath"
        "reflect"
+       "regexp"
        "strconv"
        "strings"
        "sync"
@@ -1134,6 +1135,18 @@
 // split plugin architecture (secrets, secrets-getter, secrets-post-renderer) 
with Helm 4.
 var helmSecretsV4SplitMinVersion = semver.MustParse("4.7.0")
 
+// pluginMissingRe matches helm's "plugin absent" error emitted by `helm plugin
+// uninstall` when the plugin is not installed:
+//
+//     Helm 4: "plugin: <name> not found"
+//     Helm 3: "Plugin: <name> not found"
+//
+// It is intentionally specific so that unrelated failures that happen to 
contain
+// "not found" (e.g. a missing helm binary -> "executable file not found", or 
an
+// uninstall hook failing with "sh: ...: not found") are NOT mistaken for an
+// absent plugin. It is case-insensitive and scoped to a single line.
+var pluginMissingRe = regexp.MustCompile(`(?i)plugin: .* not found`)
+
 // helmSecretsRequiresSplitInstall returns true when the given helm-secrets 
version
 // requires the split plugin architecture introduced in v4.7.0 for Helm 4.
 func helmSecretsRequiresSplitInstall(version string) bool {
@@ -1167,22 +1180,28 @@
                return helm.installHelmSecretsV4(version)
        }
 
-       // Try standard helm plugin update
-       out, err := helm.exec([]string{"plugin", "update", name}, 
map[string]string{}, nil)
-       helm.info(out)
-       if err != nil {
-               // If standard update failed, fall back to uninstall + 
reinstall with specific version
-               updateErr := err
-               helm.logger.Infof("helm plugin update %v failed (%v), falling 
back to reinstall with version %v", name, updateErr, version)
-               if uninstallErr := helm.uninstallPlugin(name); uninstallErr != 
nil {
-                       return fmt.Errorf("helm plugin update failed (%w) and 
uninstall for reinstall also failed: %w", updateErr, uninstallErr)
-               }
-               if reinstallErr := helm.AddPlugin(name, repo, version); 
reinstallErr != nil {
-                       return fmt.Errorf("helm plugin update failed (%w) and 
reinstall also failed: %w", updateErr, reinstallErr)
+       // `helm plugin update` re-installs the plugin from its cached source 
WITHOUT the
+       // `--version` flag, so it does not reliably install the specific 
version we need.
+       // On many setups it reports success (exit code 0) while `helm plugin 
list` still
+       // shows the old version, because the cached source is re-downloaded 
unchanged.
+       // See https://github.com/helmfile/helmfile/issues/2726 and
+       // https://github.com/helmfile/helmfile/issues/2548.
+       //
+       // The reliable way to update to a pinned version is to uninstall the 
existing
+       // plugin and reinstall it at the requested version. Only the expected
+       // "plugin already absent" case is tolerated: helm reports it as
+       // "plugin: <name> not found" (Helm 4) / "Plugin: <name> not found" 
(Helm 3).
+       // We match that specific message rather than a bare "not found", so 
that other
+       // failures (permissions, a missing helm binary whose error contains
+       // "executable file not found", a plugin uninstall hook failing with
+       // "sh: ...: not found", ...) are surfaced instead of being silently 
ignored.
+       if err := helm.uninstallPlugin(name); err != nil {
+               if !pluginMissingRe.MatchString(err.Error()) {
+                       return fmt.Errorf("failed to uninstall helm plugin %q 
for reinstall: %w", name, err)
                }
-               return nil
+               helm.logger.Debugf("helm plugin %v not present during update, 
proceeding to install: %v", name, err)
        }
-       return nil
+       return helm.AddPlugin(name, repo, version)
 }
 
 func (helm *execer) exec(args []string, env map[string]string, 
overrideEnableLiveOutput *bool) ([]byte, error) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helmfile-1.7.2/pkg/helmexec/exec_test.go 
new/helmfile-1.7.3/pkg/helmexec/exec_test.go
--- old/helmfile-1.7.2/pkg/helmexec/exec_test.go        2026-07-31 
16:22:31.000000000 +0200
+++ new/helmfile-1.7.3/pkg/helmexec/exec_test.go        2026-08-04 
12:31:11.000000000 +0200
@@ -20,6 +20,14 @@
        "go.uber.org/zap"
 )
 
+// pluginCmd is the "plugin" helm subcommand used repeatedly across these 
tests.
+// Extracted as constants so the repeated string literals do not trip goconst
+// (min-occurrences: 8) once additional plugin tests are added.
+const (
+       pluginCmd  = "plugin"
+       installCmd = "install"
+)
+
 // Mocking the command-line runner
 
 type mockRunner struct {
@@ -1917,7 +1925,7 @@
        // Verify that "plugin update" was NOT called (the Helm 4 secrets path 
should skip it).
        for _, args := range calledArgs {
                for i, a := range args {
-                       if a == "plugin" && i+1 < len(args) && args[i+1] == 
"update" {
+                       if a == pluginCmd && i+1 < len(args) && args[i+1] == 
"update" {
                                t.Errorf("expected 'plugin update' to not be 
called for Helm 4 secrets, but it was: %v", args)
                        }
                }
@@ -1927,7 +1935,7 @@
        checkUninstall := func(name string) {
                for _, args := range calledArgs {
                        for i, a := range args {
-                               if a == "plugin" && i+2 < len(args) && 
args[i+1] == "uninstall" && args[i+2] == name {
+                               if a == pluginCmd && i+2 < len(args) && 
args[i+1] == "uninstall" && args[i+2] == name {
                                        return
                                }
                        }
@@ -1942,7 +1950,7 @@
        checkInstall := func(urlSubstring string) {
                for _, args := range calledArgs {
                        for i, a := range args {
-                               if a == "plugin" && i+2 < len(args) && 
args[i+1] == "install" && strings.Contains(args[i+2], urlSubstring) {
+                               if a == pluginCmd && i+2 < len(args) && 
args[i+1] == installCmd && strings.Contains(args[i+2], urlSubstring) {
                                        return
                                }
                        }
@@ -1954,6 +1962,204 @@
        checkInstall("secrets-post-renderer-4.7.0.tgz")
 }
 
+// Test_UpdatePlugin_GeneralPathUsesUninstallReinstall verifies that for a 
regular
+// plugin, UpdatePlugin does NOT rely on the unreliable `helm plugin update`
+// command. Instead it must uninstall the existing plugin and reinstall the 
exact
+// pinned version. See issues #2726 and #2548: `helm plugin update` reports
+// success but leaves `helm plugin list` showing the old version because it
+// re-installs from the cached source without the --version flag.
+func Test_UpdatePlugin_GeneralPathUsesUninstallReinstall(t *testing.T) {
+       var calledArgs [][]string
+       runner := &funcRunner{
+               execute: func(cmd string, args []string, env map[string]string, 
enableLiveOutput bool) ([]byte, error) {
+                       calledArgs = append(calledArgs, append([]string(nil), 
args...))
+                       return []byte{}, nil
+               },
+       }
+
+       var buffer bytes.Buffer
+       logger := NewLogger(&buffer, "debug")
+       helm := &execer{
+               helmBinary: "helm",
+               version:    semver.MustParse("3.16.4"),
+               logger:     logger,
+               runner:     runner,
+       }
+
+       err := helm.UpdatePlugin("diff", 
"https://github.com/databus23/helm-diff";, "v3.15.10")
+       require.NoError(t, err)
+
+       // `plugin update` must never be used: it does not honor --version and 
silently
+       // leaves the old version installed.
+       for _, args := range calledArgs {
+               for i, a := range args {
+                       if a == pluginCmd && i+1 < len(args) && args[i+1] == 
"update" {
+                               t.Errorf("expected 'plugin update' to not be 
called, but it was: %v", args)
+                       }
+               }
+       }
+
+       // `plugin uninstall diff` must be called to clear the stale version.
+       uninstalled := false
+       for _, args := range calledArgs {
+               for i, a := range args {
+                       if a == pluginCmd && i+2 < len(args) && args[i+1] == 
"uninstall" && args[i+2] == "diff" {
+                               uninstalled = true
+                       }
+               }
+       }
+       require.True(t, uninstalled, "expected 'plugin uninstall diff' to be 
called")
+
+       // `plugin install <repo> --version <pinned>` must be called with the 
exact
+       // requested version so the installed plugin is updated to it.
+       installed := false
+       for _, args := range calledArgs {
+               for i, a := range args {
+                       if a == pluginCmd && i+1 < len(args) && args[i+1] == 
installCmd {
+                               hasRepo := false
+                               hasVersion := false
+                               for _, arg := range args[i+2:] {
+                                       if arg == 
"https://github.com/databus23/helm-diff"; {
+                                               hasRepo = true
+                                       }
+                                       if arg == "v3.15.10" {
+                                               hasVersion = true
+                                       }
+                               }
+                               if hasRepo && hasVersion {
+                                       installed = true
+                               }
+                       }
+               }
+       }
+       require.True(t, installed, "expected 'plugin install' with the pinned 
version to be called")
+}
+
+// Test_UpdatePlugin_NotFoundUninstallProceedsToInstall ensures that when the
+// plugin is already absent (helm reports its "plugin not found" message),
+// UpdatePlugin still proceeds to install the pinned version rather than 
treating
+// it as an error. Both helm major formats are covered.
+func Test_UpdatePlugin_NotFoundUninstallProceedsToInstall(t *testing.T) {
+       // Helm 4 reports "plugin: <name> not found"; Helm 3 reports "Plugin: 
<name> not found".
+       for _, tc := range []struct {
+               name    string
+               version string
+               msg     string
+       }{
+               {name: "helm4", version: "4.2.3", msg: "plugin: diff not 
found"},
+               {name: "helm3", version: "3.16.4", msg: "Plugin: diff not 
found"},
+       } {
+               t.Run(tc.name, func(t *testing.T) {
+                       var calledArgs [][]string
+                       runner := &funcRunner{
+                               execute: func(cmd string, args []string, env 
map[string]string, enableLiveOutput bool) ([]byte, error) {
+                                       calledArgs = append(calledArgs, 
append([]string(nil), args...))
+                                       if len(args) >= 2 && args[0] == 
pluginCmd && args[1] == "uninstall" {
+                                               return nil, ExitError{Message: 
tc.msg, Code: 1}
+                                       }
+                                       return []byte{}, nil
+                               },
+                       }
+
+                       var buffer bytes.Buffer
+                       logger := NewLogger(&buffer, "debug")
+                       helm := &execer{
+                               helmBinary: "helm",
+                               version:    semver.MustParse(tc.version),
+                               logger:     logger,
+                               runner:     runner,
+                       }
+
+                       err := helm.UpdatePlugin("diff", 
"https://github.com/databus23/helm-diff";, "v3.15.10")
+                       require.NoError(t, err, "a plugin-absent uninstall 
error should be ignored and install should proceed")
+
+                       // install with the pinned version must still be 
attempted
+                       installed := false
+                       for _, args := range calledArgs {
+                               for i, a := range args {
+                                       if a == pluginCmd && i+1 < len(args) && 
args[i+1] == installCmd {
+                                               for _, arg := range args[i+2:] {
+                                                       if arg == "v3.15.10" {
+                                                               installed = true
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       require.True(t, installed, "expected install to proceed 
after a plugin-absent uninstall")
+               })
+       }
+}
+
+// Test_UpdatePlugin_RealUninstallFailureReturnsError ensures that a genuine
+// uninstall failure (permissions, broken Helm, etc.) is surfaced instead of
+// being ignored, which would otherwise mask the root cause behind a confusing
+// "plugin already exists" error from the subsequent install.
+func Test_UpdatePlugin_RealUninstallFailureReturnsError(t *testing.T) {
+       installCalled := false
+       runner := &funcRunner{
+               execute: func(cmd string, args []string, env map[string]string, 
enableLiveOutput bool) ([]byte, error) {
+                       if len(args) >= 2 && args[0] == pluginCmd && args[1] == 
"uninstall" {
+                               return nil, ExitError{Message: "permission 
denied", Code: 1}
+                       }
+                       if len(args) >= 2 && args[0] == pluginCmd && args[1] == 
installCmd {
+                               installCalled = true
+                       }
+                       return []byte{}, nil
+               },
+       }
+
+       var buffer bytes.Buffer
+       logger := NewLogger(&buffer, "debug")
+       helm := &execer{
+               helmBinary: "helm",
+               version:    semver.MustParse("3.16.4"),
+               logger:     logger,
+               runner:     runner,
+       }
+
+       err := helm.UpdatePlugin("diff", 
"https://github.com/databus23/helm-diff";, "v3.15.10")
+       require.Error(t, err, "a real uninstall failure should be returned")
+       assert.Contains(t, err.Error(), "uninstall")
+       assert.False(t, installCalled, "install must not be attempted after a 
real uninstall failure")
+}
+
+// Test_UpdatePlugin_ExecutableNotFoundUninstallErrorIsNotSwallowed guards 
against
+// an overly broad "not found" check: when helm itself is missing the runner
+// surfaces an error containing "executable file not found", which must NOT be
+// mistaken for an absent plugin (otherwise UpdatePlugin would silently log and
+// proceed to install, masking the real problem). Only the helm-specific
+// "plugin: <name> not found" message is tolerated.
+func Test_UpdatePlugin_ExecutableNotFoundUninstallErrorIsNotSwallowed(t 
*testing.T) {
+       installCalled := false
+       runner := &funcRunner{
+               execute: func(cmd string, args []string, env map[string]string, 
enableLiveOutput bool) ([]byte, error) {
+                       if len(args) >= 2 && args[0] == pluginCmd && args[1] == 
"uninstall" {
+                               // Mimics helmfile's ShellRunner when the helm 
binary is absent.
+                               return nil, fmt.Errorf("unexpected error: exec: 
%q: executable file not found in $PATH", cmd)
+                       }
+                       if len(args) >= 2 && args[0] == pluginCmd && args[1] == 
installCmd {
+                               installCalled = true
+                       }
+                       return []byte{}, nil
+               },
+       }
+
+       var buffer bytes.Buffer
+       logger := NewLogger(&buffer, "debug")
+       helm := &execer{
+               helmBinary: "helm",
+               version:    semver.MustParse("3.16.4"),
+               logger:     logger,
+               runner:     runner,
+       }
+
+       err := helm.UpdatePlugin("diff", 
"https://github.com/databus23/helm-diff";, "v3.15.10")
+       require.Error(t, err, "a missing-binary uninstall error must be 
returned, not swallowed")
+       assert.Contains(t, err.Error(), "executable file not found")
+       assert.False(t, installCalled, "install must not be attempted when the 
helm binary is missing")
+}
+
 func Test_dedupeWroteLines(t *testing.T) {
        cases := []struct {
                name string
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helmfile-1.7.2/pkg/state/issue_1757_test.go 
new/helmfile-1.7.3/pkg/state/issue_1757_test.go
--- old/helmfile-1.7.2/pkg/state/issue_1757_test.go     1970-01-01 
01:00:00.000000000 +0100
+++ new/helmfile-1.7.3/pkg/state/issue_1757_test.go     2026-08-04 
12:31:11.000000000 +0200
@@ -0,0 +1,200 @@
+package state
+
+import (
+       "errors"
+       "os"
+       "os/exec"
+       "path/filepath"
+       "runtime"
+       "testing"
+
+       "github.com/helmfile/chartify"
+       "github.com/stretchr/testify/assert"
+       "github.com/stretchr/testify/require"
+       "go.uber.org/zap"
+
+       "github.com/helmfile/helmfile/pkg/filesystem"
+)
+
+// TestIsChartifyEmptyRenderOutputError verifies that 
isChartifyEmptyRenderOutputError
+// only matches chartify's specific "empty rendered output dir" assertion 
failure, not
+// other, unrelated chartify errors. This is a regression test for issue 
#1757: a chart
+// that renders zero resources (e.g. everything gated behind a falsy `if`) 
combined with
+// transformers/jsonPatches/strategicMergePatches used to crash helmfile with
+//
+//     assertion failed: unexpected dir entry "" it must be the abs path to 
the output directory
+//
+// because chartify expects exactly one rendered output directory and found 
none.
+func TestIsChartifyEmptyRenderOutputError(t *testing.T) {
+       tests := []struct {
+               name     string
+               err      error
+               expected bool
+       }{
+               {
+                       name:     "nil error",
+                       err:      nil,
+                       expected: false,
+               },
+               {
+                       name:     "chartify empty render assertion error",
+                       err:      errors.New(`assertion failed: unexpected dir 
entry "" it must be the abs path to the output directory`),
+                       expected: true,
+               },
+               {
+                       // Same assertion, but chartOutputDir is a non-empty 
(merely
+                       // relative) path rather than "" - a different, 
hypothetical
+                       // chartify bug that happens to trip the same final 
assertion.
+                       // This must NOT be treated as the empty-render no-op 
case:
+                       // per review feedback 
(https://github.com/helmfile/helmfile/pull/2724),
+                       // matching only on the trailing "...it must be the abs 
path to
+                       // the output directory" phrase (without requiring the 
`""`
+                       // empty-string dir entry) would have incorrectly 
matched this
+                       // too, silently masking a genuinely different failure.
+                       name:     "same assertion with a non-empty dir entry is 
not the empty-render case",
+                       err:      errors.New(`assertion failed: unexpected dir 
entry "relative/path" it must be the abs path to the output directory`),
+                       expected: false,
+               },
+               {
+                       name:     "unrelated chartify error",
+                       err:      errors.New("exec: \"kustomize\": executable 
file not found in %PATH%"),
+                       expected: false,
+               },
+               {
+                       name:     "unrelated multiple-dir-entries assertion",
+                       err:      errors.New(`assertion failed: there should be 
only one dir entry under the helm output dir /tmp/foo`),
+                       expected: false,
+               },
+               {
+                       name:     "helm template failure",
+                       err:      errors.New("Error: template: 
mychart/templates/broken.yaml:3:5: executing..."),
+                       expected: false,
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       assert.Equal(t, tt.expected, 
isChartifyEmptyRenderOutputError(tt.err))
+               })
+       }
+}
+
+// TestProcessChartification_EmptyRenderReturnsSurvivingPath is an end-to-end
+// regression test for a bug found in review of the #1757 fix: the empty-render
+// no-op path must return the chart's original path, not the temp copy that
+// rewriteChartDependencies creates when the chart has relative file:// deps -
+// that temp dir is removed by a deferred cleanup as soon as 
processChartification
+// returns, so returning it would hand the caller a path to a directory that no
+// longer exists on disk.
+//
+// This exercises the real processChartification -> chartify.Chartify wiring
+// (unlike TestIsChartifyEmptyRenderOutputError above, which only tests the 
pure
+// string-matching helper), so it needs real helm and kustomize binaries on 
PATH
+// and is skipped if either is missing. Verified to pass on Linux; skipped on
+// Windows because the file:// dependency URL this test needs (to make
+// rewriteChartDependencies actually produce a temp copy) hits an unrelated,
+// pre-existing Windows path-handling issue in chartify/helm's dependency
+// resolution (a Windows drive letter embedded in a file:// URL gets
+// mis-joined onto another path), independent of the fix under test here.
+func TestProcessChartification_EmptyRenderReturnsSurvivingPath(t *testing.T) {
+       if runtime.GOOS == "windows" {
+               t.Skip("skipping on Windows: unrelated file:// dependency URL / 
drive letter handling issue in chartify's helm dependency resolution, not the 
code path under test; passes on Linux (CI)")
+       }
+       if _, err := exec.LookPath("helm"); err != nil {
+               t.Skip("helm not found on PATH, skipping")
+       }
+       if _, err := exec.LookPath("kustomize"); err != nil {
+               t.Skip("kustomize not found on PATH, skipping")
+       }
+
+       tempDir := t.TempDir()
+
+       // A sibling chart referenced via a relative file:// dependency, so that
+       // processChartification takes the rewriteChartDependencies path (line
+       // `if st.fs.DirectoryExistsAt(chartPath) { ... }`) and reassigns its 
local
+       // chartPath variable to a temp copy before ever calling chartify.
+       depChartDir := filepath.Join(tempDir, "dep-chart")
+       require.NoError(t, os.MkdirAll(depChartDir, 0755))
+       require.NoError(t, os.WriteFile(filepath.Join(depChartDir, 
"Chart.yaml"), []byte(`
+apiVersion: v2
+name: dep-chart
+version: 0.1.0
+`), 0644))
+
+       chartDir := filepath.Join(tempDir, "chart")
+       require.NoError(t, os.MkdirAll(filepath.Join(chartDir, "templates"), 
0755))
+       require.NoError(t, os.WriteFile(filepath.Join(chartDir, "Chart.yaml"), 
[]byte(`
+apiVersion: v2
+name: emptychart
+version: 0.1.0
+dependencies:
+  - name: dep-chart
+    version: 0.1.0
+    repository: "file://../dep-chart"
+`), 0644))
+       require.NoError(t, os.WriteFile(filepath.Join(chartDir, "values.yaml"), 
[]byte("enabled: false\n"), 0644))
+       // Every template is gated behind a falsy condition, so helm renders 
zero
+       // resources - the exact condition that triggers chartify's empty-output
+       // assertion.
+       require.NoError(t, os.WriteFile(filepath.Join(chartDir, "templates", 
"deployment.yaml"), []byte(`
+{{- if .Values.enabled }}
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: test
+{{- end }}
+`), 0644))
+
+       // A transformer is required for chartify to be invoked at all (see the
+       // call site in state.go: chartification is only non-nil, and 
processChartification
+       // only gets called, when 
transformers/jsonPatches/strategicMergePatches are set).
+       transformerPath := filepath.Join(tempDir, "transformer.yaml")
+       require.NoError(t, os.WriteFile(transformerPath, []byte(`
+apiVersion: builtin
+kind: AnnotationsTransformer
+metadata:
+  name: notImportantHere
+annotations:
+  area: "51"
+fieldSpecs:
+  - path: metadata/annotations
+    create: true
+`), 0644))
+
+       st := &HelmState{
+               logger: zap.NewNop().Sugar(),
+               fs:     filesystem.DefaultFileSystem(),
+               ReleaseSetSpec: ReleaseSetSpec{
+                       DefaultHelmBinary:      "helm",
+                       DefaultKustomizeBinary: "kustomize",
+               },
+       }
+
+       chartification := &Chartify{
+               Opts: &chartify.ChartifyOpts{
+                       Transformers: []string{transformerPath},
+               },
+       }
+       release := &ReleaseSpec{}
+       release.Name = "empty-release"
+
+       resultPath, buildDeps, err := st.processChartification(
+               chartification, release, chartDir, ChartPrepareOptions{}, 
false, "template",
+       )
+
+       require.NoError(t, err)
+       assert.True(t, buildDeps, "buildDeps should be true (!skipDeps) for the 
no-op path")
+
+       // The returned path must still exist: it must be the original chart
+       // directory, not the deps-rewritten temp copy that gets deleted by
+       // rewriteChartDependencies' deferred cleanup on return.
+       info, statErr := os.Stat(resultPath)
+       require.NoError(t, statErr, "returned chart path %q must still exist 
after processChartification returns", resultPath)
+       assert.True(t, info.IsDir())
+
+       // It should specifically be the chart's own directory (or an
+       // equally-valid, not-yet-cleaned-up path to the same chart), not some
+       // other temp directory. Chart.yaml must be readable from it.
+       _, err = os.Stat(filepath.Join(resultPath, "Chart.yaml"))
+       assert.NoError(t, err, "Chart.yaml should be reachable from the 
returned path %q", resultPath)
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helmfile-1.7.2/pkg/state/state.go 
new/helmfile-1.7.3/pkg/state/state.go
--- old/helmfile-1.7.2/pkg/state/state.go       2026-07-31 16:22:31.000000000 
+0200
+++ new/helmfile-1.7.3/pkg/state/state.go       2026-08-04 12:31:11.000000000 
+0200
@@ -1868,6 +1868,11 @@
 // If exists, it will also patch resources by json patches, strategic-merge 
patches, and injectors.
 // processChartification handles the chartification process
 func (st *HelmState) processChartification(chartification *Chartify, release 
*ReleaseSpec, chartPath string, opts ChartPrepareOptions, skipDeps bool, 
helmfileCommand string) (string, bool, error) {
+       // Preserved so the empty-render no-op path below can return this 
instead of the
+       // deps-rewritten temp copy assigned to chartPath further down, which 
the deferred
+       // cleanupTempChart() removes as soon as this function returns.
+       originalChartPath := chartPath
+
        // Rewrite relative file:// dependencies in Chart.yaml to absolute 
paths before chartify processes them
        // This prevents errors like "Error: directory 
/tmp/chartify.../argocd-application not found"
        // when Chart.yaml contains dependencies like 
"file://../argocd-application"
@@ -1939,6 +1944,21 @@
        )
 
        out, err := c.Chartify(release.Name, chartPath, 
chartify.WithChartifyOpts(chartifyOpts))
+       if err != nil && isChartifyEmptyRenderOutputError(err) {
+               // The chart rendered zero resources (e.g. everything is gated 
behind a
+               // `{{- if .Values.enabled }}` that evaluated to false), so 
chartify has
+               // nothing to replace templates/charts/crds with and fails its 
internal
+               // "there must be exactly one rendered output dir" assertion. 
Treat this
+               // as a no-op: use the chart as-is, since there's nothing to 
chartify.
+               // See https://github.com/helmfile/helmfile/issues/1757 and the 
upstream
+               // tracking issue 
https://github.com/helmfile/chartify/issues/206.
+               st.logger.Debugf("release %q: chart rendered no resources, 
skipping chartification: %v", release.Name, err)
+               // Return originalChartPath, NOT chartPath: chartPath may have 
been reassigned
+               // above to the deps-rewritten temp copy, which the deferred 
cleanupTempChart()
+               // removes as soon as this function returns. Since chartify 
never actually ran,
+               // relative file:// deps resolve fine from the original 
location anyway.
+               return originalChartPath, !skipDeps, nil
+       }
        if err != nil {
                return "", false, err
        }
@@ -1954,6 +1974,34 @@
        return chartPath, buildDeps, nil
 }
 
+// chartifyEmptyRenderOutputErrSubstring is the distinctive part of the error 
that
+// github.com/helmfile/chartify (as of v0.28.0, see replace.go) returns when 
`helm template`
+// renders zero resources for a chart: it expects exactly one directory entry 
under its
+// `--output-dir`, and an empty render leaves that directory empty, so the 
"must be the abs
+// path to the output directory" assertion fails on the resulting empty 
string. Chartify does
+// not expose a typed/sentinel error for this case, so we match on the error 
text.
+//
+// The matched string includes the `unexpected dir entry ""` prefix (not just 
the trailing
+// "...it must be the abs path to the output directory" phrase) so this can 
only match when
+// chartify's chartOutputDir was genuinely empty - i.e. the exact empty-render 
case - and not
+// some other, hypothetical failure of the same assertion against a non-empty 
(but still
+// relative) path, which would be a different bug that should still be 
surfaced as an error.
+//
+// If this substring ever stops matching a real chartify error, chartify's 
wording has
+// changed and this check needs to be revisited.
+//
+// Tracked upstream at https://github.com/helmfile/chartify/issues/206 - once 
chartify
+// exposes a sentinel error (or treats an empty render as a no-op itself) and 
this repo
+// bumps to that version, this text match can be retired.
+const chartifyEmptyRenderOutputErrSubstring = `unexpected dir entry "" it must 
be the abs path to the output directory`
+
+// isChartifyEmptyRenderOutputError reports whether err is chartify's 
assertion failure caused
+// by a chart rendering zero resources, as opposed to some other, unrelated 
chartify failure
+// that should still be surfaced to the user.
+func isChartifyEmptyRenderOutputError(err error) bool {
+       return err != nil && strings.Contains(err.Error(), 
chartifyEmptyRenderOutputErrSubstring)
+}
+
 func (st *HelmState) 
appendSkipSchemaValidationFlagToChartifyTemplateArgs(templateArgs string, 
release *ReleaseSpec, skipSchemaValidation bool) string {
        if !st.shouldSkipSchemaValidation(release, skipSchemaValidation) || 
hasTemplateArg(templateArgs, "--skip-schema-validation") {
                return templateArgs
@@ -2942,7 +2990,7 @@
                                }
 
                                var disableValidation bool
-                               if release.DisableValidationOnInstall != nil && 
*release.DisableValidationOnInstall {
+                               if (release.DisableValidationOnInstall != nil 
&& *release.DisableValidationOnInstall) || opt.SkipDiffValidationOnInstall {
                                        installed, err := isInstalled(release)
                                        if err != nil {
                                                errs = append(errs, err)
@@ -3042,11 +3090,12 @@
        Color bool
        // NoColor forces disabling the color output on helm-diff.
        // If this is true, Color has no effect.
-       NoColor           bool
-       Set               []string
-       SkipCleanup       bool
-       SkipDiffOnInstall bool
-       DiffArgs          string
+       NoColor                     bool
+       Set                         []string
+       SkipCleanup                 bool
+       SkipDiffOnInstall           bool
+       SkipDiffValidationOnInstall bool
+       DiffArgs                    string
        // TemplateArgs are extra args appended to the helm template/diff 
rendering
        // (e.g. "--dry-run=server" to enable the helm lookup function during 
`helmfile
        // apply`/`diff`, which render via helm-diff). See issue #1833.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helmfile-1.7.2/pkg/state/state_test.go 
new/helmfile-1.7.3/pkg/state/state_test.go
--- old/helmfile-1.7.2/pkg/state/state_test.go  2026-07-31 16:22:31.000000000 
+0200
+++ new/helmfile-1.7.3/pkg/state/state_test.go  2026-08-04 12:31:11.000000000 
+0200
@@ -4268,6 +4268,87 @@
        }
 }
 
+func TestPrepareDiffReleases_SkipDiffValidationOnInstall(t *testing.T) {
+       installedListOutput := 
"NAME\tNAMESPACE\tREVISION\tSTATUS\nfoo\tdefault\t1\tdeployed"
+       listFlags := "--uninstalling --deployed --failed --pending"
+
+       tests := []struct {
+               name                        string
+               skipDiffValidationOnInstall bool
+               perReleaseDisableValidation bool
+               installed                   bool
+               wantDisableValidation       bool
+       }{
+               {
+                       name:                        "flag-set-not-installed",
+                       skipDiffValidationOnInstall: true,
+                       installed:                   false,
+                       wantDisableValidation:       true,
+               },
+               {
+                       name:                        
"flag-set-already-installed",
+                       skipDiffValidationOnInstall: true,
+                       installed:                   true,
+                       wantDisableValidation:       false,
+               },
+               {
+                       name:                        
"flag-not-set-not-installed",
+                       skipDiffValidationOnInstall: false,
+                       installed:                   false,
+                       wantDisableValidation:       false,
+               },
+               {
+                       name:                        
"per-release-flag-not-installed",
+                       perReleaseDisableValidation: true,
+                       installed:                   false,
+                       wantDisableValidation:       true,
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       release := ReleaseSpec{
+                               Name:  "foo",
+                               Chart: "stable/foo",
+                       }
+                       if tt.perReleaseDisableValidation {
+                               release.DisableValidationOnInstall = 
boolValue(true)
+                       }
+                       st := &HelmState{
+                               ReleaseSetSpec: ReleaseSetSpec{
+                                       Releases:     []ReleaseSpec{release},
+                                       HelmDefaults: HelmSpec{},
+                               },
+                               logger:      logger,
+                               valsRuntime: valsRuntime,
+                       }
+                       lists := map[exectest.ListKey]string{}
+                       if tt.installed {
+                               lists[exectest.ListKey{Filter: "^foo$", Flags: 
listFlags}] = installedListOutput
+                       }
+                       helm := &exectest.Helm{Lists: lists}
+
+                       results, errs := st.prepareDiffReleases(helm, 
[]string{}, 1, false, false, false, []string{}, false, false, false, &DiffOpts{
+                               SkipDiffValidationOnInstall: 
tt.skipDiffValidationOnInstall,
+                       })
+
+                       require.Len(t, errs, 0)
+                       require.Len(t, results, 1)
+
+                       flags := results[0].flags
+                       hasDisableValidation := false
+                       for _, f := range flags {
+                               if f == "--disable-validation" {
+                                       hasDisableValidation = true
+                                       break
+                               }
+                       }
+                       require.Equal(t, tt.wantDisableValidation, 
hasDisableValidation,
+                               "--disable-validation presence mismatch for 
case %q; flags: %v", tt.name, flags)
+               })
+       }
+}
+
 func TestPrepareSyncReleases(t *testing.T) {
        tests := []struct {
                name         string

++++++ vendor.tar.gz ++++++
/work/SRC/openSUSE:Factory/helmfile/vendor.tar.gz 
/work/SRC/openSUSE:Factory/.helmfile.new.16738/vendor.tar.gz differ: char 121, 
line 1

Reply via email to