Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package helm for openSUSE:Factory checked in 
at 2026-08-22 21:35:21
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/helm (Old)
 and      /work/SRC/openSUSE:Factory/.helm.new.1258 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "helm"

Sat Aug 22 21:35:21 2026 rev:112 rq:1372954 version:4.2.4

Changes:
--------
--- /work/SRC/openSUSE:Factory/helm/helm.changes        2026-07-28 
18:08:57.219741159 +0200
+++ /work/SRC/openSUSE:Factory/.helm.new.1258/helm.changes      2026-08-22 
21:37:30.054131173 +0200
@@ -1,0 +2,30 @@
+Fri Aug 21 22:06:09 UTC 2026 - Dirk Müller <[email protected]>
+
+- update vendor.tar to fix
+  * bsc#1275025, CVE-2026-56864
+  * bsc#1275024, CVE-2026-56865
+  * bsc#1271462, CVE-2026-50163
+
+-------------------------------------------------------------------
+Fri Aug 14 05:28:46 UTC 2026 - Johannes Kastl 
<[email protected]>
+
+- update to 4.2.4:
+  * fix: Improve error reporting for helm template --debug with
+    --show-only- #31185
+  * fix: fetch logs from all containers in test pods- #32099
+  * fix(provenance): check error return in Digest and
+    encodeRelease- #32136
+  * fix panic on repeated IsReachable calls- #32184
+  * fix: set [pull,push] scope when helm push to a registry(use
+    token auth) - v4- #31211
+  * Fix missing conflict retry with server-side apply- #32088
+  * Properly format the extra field in gzipped packages- #31884
+  * Fix vanishing empty lines- #32327
+  * fix: pass registry client to downloader.Manager in upgrade-
+    #32400
+  * chore(deps): bump google.golang.org/grpc from 1.80.0 to 1.82.1-
+    #32450
+  * fix: bump go.opentelemetry.io/otel to v1.44.0 for GO-2026-5158-
+    #32521
+
+-------------------------------------------------------------------

Old:
----
  helm-4.2.3.obscpio
  vendor.tar.gz

New:
----
  helm-4.2.4.obscpio
  vendor.tar.zst

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

Other differences:
------------------
++++++ helm.spec ++++++
--- /var/tmp/diff_new_pack.vMvqPH/_old  2026-08-22 21:37:31.627187403 +0200
+++ /var/tmp/diff_new_pack.vMvqPH/_new  2026-08-22 21:37:31.629187475 +0200
@@ -17,14 +17,14 @@
 
 
 Name:           helm
-Version:        4.2.3
+Version:        4.2.4
 Release:        0
 Summary:        The Kubernetes Package Manager
 License:        Apache-2.0
 Group:          Development/Languages/Other
 URL:            https://github.com/helm/helm
 Source0:        %{name}-%{version}.tar.gz
-Source1:        vendor.tar.gz
+Source1:        vendor.tar.zst
 Patch1:         CVE-2026-63308.patch
 BuildRequires:  bash-completion
 BuildRequires:  fish

++++++ _service ++++++
--- /var/tmp/diff_new_pack.vMvqPH/_old  2026-08-22 21:37:31.668188869 +0200
+++ /var/tmp/diff_new_pack.vMvqPH/_new  2026-08-22 21:37:31.672189012 +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">refs/tags/v4.2.3</param>
+    <param name="revision">refs/tags/v4.2.4</param>
     <param name="changesgenerate">disable</param>
   </service>
   <service name="set_version" mode="manual">
@@ -16,7 +16,10 @@
     <param name="compression">gz</param>
   </service>
   <service name="go_modules" mode="manual">
+    <param name="compression">zst</param>
     <param name="replace">golang.org/x/net=golang.org/x/[email protected]</param>
+    <param name="replace">golang.org/x/mod=golang.org/x/[email protected]</param>
+    <param 
name="replace">oras.land/oras-go/v2=oras.land/oras-go/[email protected]</param>
   </service>
 </services>
 

++++++ helm-4.2.3.obscpio -> helm-4.2.4.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helm-4.2.3/go.mod new/helm-4.2.4/go.mod
--- old/helm-4.2.3/go.mod       2026-07-09 22:15:44.000000000 +0200
+++ new/helm-4.2.4/go.mod       2026-08-13 16:46:03.000000000 +0200
@@ -80,6 +80,7 @@
        github.com/fxamacker/cbor/v2 v2.9.0 // indirect
        github.com/go-errors/errors v1.5.1 // indirect
        github.com/go-gorp/gorp/v3 v3.1.0 // indirect
+       github.com/go-jose/go-jose/v4 v4.1.4 // indirect
        github.com/go-logr/logr v1.4.3 // indirect
        github.com/go-logr/stdr v1.2.2 // indirect
        github.com/go-openapi/jsonpointer v0.21.1 // indirect
@@ -137,7 +138,7 @@
        go.opentelemetry.io/contrib/bridges/prometheus v0.67.0 // indirect
        go.opentelemetry.io/contrib/exporters/autoexport v0.67.0 // indirect
        go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 
// indirect
-       go.opentelemetry.io/otel v1.43.0 // indirect
+       go.opentelemetry.io/otel v1.44.0 // indirect
        go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.18.0 // 
indirect
        go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.19.0 // 
indirect
        go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc 
v1.42.0 // indirect
@@ -150,11 +151,11 @@
        go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.42.0 // 
indirect
        go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.42.0 // 
indirect
        go.opentelemetry.io/otel/log v0.19.0 // indirect
-       go.opentelemetry.io/otel/metric v1.43.0 // indirect
-       go.opentelemetry.io/otel/sdk v1.43.0 // indirect
+       go.opentelemetry.io/otel/metric v1.44.0 // indirect
+       go.opentelemetry.io/otel/sdk v1.44.0 // indirect
        go.opentelemetry.io/otel/sdk/log v0.19.0 // indirect
-       go.opentelemetry.io/otel/sdk/metric v1.43.0 // indirect
-       go.opentelemetry.io/otel/trace v1.43.0 // indirect
+       go.opentelemetry.io/otel/sdk/metric v1.44.0 // indirect
+       go.opentelemetry.io/otel/trace v1.44.0 // indirect
        go.opentelemetry.io/proto/otlp v1.10.0 // indirect
        go.yaml.in/yaml/v2 v2.4.3 // indirect
        golang.org/x/mod v0.37.0 // indirect
@@ -164,9 +165,9 @@
        golang.org/x/sys v0.47.0 // indirect
        golang.org/x/time v0.15.0 // indirect
        golang.org/x/tools v0.47.0 // indirect
-       google.golang.org/genproto/googleapis/api 
v0.0.0-20260401024825-9d38bb4040a9 // indirect
-       google.golang.org/genproto/googleapis/rpc 
v0.0.0-20260401024825-9d38bb4040a9 // indirect
-       google.golang.org/grpc v1.80.0 // indirect
+       google.golang.org/genproto/googleapis/api 
v0.0.0-20260414002931-afd174a4e478 // indirect
+       google.golang.org/genproto/googleapis/rpc 
v0.0.0-20260414002931-afd174a4e478 // indirect
+       google.golang.org/grpc v1.82.1 // indirect
        google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // 
indirect
        gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
        gopkg.in/inf.v0 v0.9.1 // indirect
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helm-4.2.3/go.sum new/helm-4.2.4/go.sum
--- old/helm-4.2.3/go.sum       2026-07-09 22:15:44.000000000 +0200
+++ new/helm-4.2.4/go.sum       2026-08-13 16:46:03.000000000 +0200
@@ -105,6 +105,8 @@
 github.com/go-errors/errors v1.5.1/go.mod 
h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
 github.com/go-gorp/gorp/v3 v3.1.0 
h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs=
 github.com/go-gorp/gorp/v3 v3.1.0/go.mod 
h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw=
+github.com/go-jose/go-jose/v4 v4.1.4 
h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA=
+github.com/go-jose/go-jose/v4 v4.1.4/go.mod 
h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
 github.com/go-kit/kit v0.8.0/go.mod 
h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 github.com/go-logfmt/logfmt v0.3.0/go.mod 
h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
 github.com/go-logfmt/logfmt v0.4.0/go.mod 
h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
@@ -326,8 +328,8 @@
 go.opentelemetry.io/contrib/exporters/autoexport v0.67.0/go.mod 
h1:qTvIHMFKoxW7HXg02gm6/Wofhq5p3Ib/A/NNt1EoBSQ=
 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 
h1:OyrsyzuttWTSur2qN/Lm0m2a8yqyIjUVBZcxFPuXq2o=
 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0/go.mod 
h1:C2NGBr+kAB4bk3xtMXfZ94gqFDtg/GkI7e9zqGh5Beg=
-go.opentelemetry.io/otel v1.43.0 
h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I=
-go.opentelemetry.io/otel v1.43.0/go.mod 
h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0=
+go.opentelemetry.io/otel v1.44.0 
h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU=
+go.opentelemetry.io/otel v1.44.0/go.mod 
h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc=
 go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.18.0 
h1:deI9UQMoGFgrg5iLPgzueqFPHevDl+28YKfSpPTI6rY=
 go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.18.0/go.mod 
h1:PFx9NgpNUKXdf7J4Q3agRxMs3Y07QhTCVipKmLsMKnU=
 go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.19.0 
h1:HIBTQ3VO5aupLKjC90JgMqpezVXwFuq6Ryjn0/izoag=
@@ -352,18 +354,20 @@
 go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.42.0/go.mod 
h1:UI3wi0FXg1Pofb8ZBiBLhtMzgoTm1TYkMvn71fAqDzs=
 go.opentelemetry.io/otel/log v0.19.0 
h1:KUZs/GOsw79TBBMfDWsXS+KZ4g2Ckzksd1ymzsIEbo4=
 go.opentelemetry.io/otel/log v0.19.0/go.mod 
h1:5DQYeGmxVIr4n0/BcJvF4upsraHjg6vudJJpnkL6Ipk=
-go.opentelemetry.io/otel/metric v1.43.0 
h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM=
-go.opentelemetry.io/otel/metric v1.43.0/go.mod 
h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY=
-go.opentelemetry.io/otel/sdk v1.43.0 
h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg=
-go.opentelemetry.io/otel/sdk v1.43.0/go.mod 
h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg=
+go.opentelemetry.io/otel/metric v1.44.0 
h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc=
+go.opentelemetry.io/otel/metric v1.44.0/go.mod 
h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo=
+go.opentelemetry.io/otel/metric/x v0.66.0 
h1:YkCrx1zLOChi9ZcZ6euupOcsgzbVlec7D/xoEU1+cTA=
+go.opentelemetry.io/otel/metric/x v0.66.0/go.mod 
h1:d1+BDj9t96do0/1LoU1ayfCv79ZgNE41qbhBvnMOBZk=
+go.opentelemetry.io/otel/sdk v1.44.0 
h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58=
+go.opentelemetry.io/otel/sdk v1.44.0/go.mod 
h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0=
 go.opentelemetry.io/otel/sdk/log v0.19.0 
h1:scYVLqT22D2gqXItnWiocLUKGH9yvkkeql5dBDiXyko=
 go.opentelemetry.io/otel/sdk/log v0.19.0/go.mod 
h1:vFBowwXGLlW9AvpuF7bMgnNI95LiW10szrOdvzBHlAg=
 go.opentelemetry.io/otel/sdk/log/logtest v0.19.0 
h1:BEbF7ZBB6qQloV/Ub1+3NQoOUnVtcGkU3XX4Ws3GQfk=
 go.opentelemetry.io/otel/sdk/log/logtest v0.19.0/go.mod 
h1:Lua81/3yM0wOmoHTokLj9y9ADeA02v1naRrVrkAZuKk=
-go.opentelemetry.io/otel/sdk/metric v1.43.0 
h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw=
-go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod 
h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A=
-go.opentelemetry.io/otel/trace v1.43.0 
h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A=
-go.opentelemetry.io/otel/trace v1.43.0/go.mod 
h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0=
+go.opentelemetry.io/otel/sdk/metric v1.44.0 
h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI=
+go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod 
h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA=
+go.opentelemetry.io/otel/trace v1.44.0 
h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk=
+go.opentelemetry.io/otel/trace v1.44.0/go.mod 
h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE=
 go.opentelemetry.io/proto/otlp v1.10.0 
h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g=
 go.opentelemetry.io/proto/otlp v1.10.0/go.mod 
h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk=
 go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
@@ -463,12 +467,12 @@
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod 
h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
 gonum.org/v1/gonum v0.17.0/go.mod 
h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
-google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 
h1:VPWxll4HlMw1Vs/qXtN7BvhZqsS9cdAittCNvVENElA=
-google.golang.org/genproto/googleapis/api 
v0.0.0-20260401024825-9d38bb4040a9/go.mod 
h1:7QBABkRtR8z+TEnmXTqIqwJLlzrZKVfAUm7tY3yGv0M=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 
h1:m8qni9SQFH0tJc1X0vmnpw/0t+AImlSvp30sEupozUg=
-google.golang.org/genproto/googleapis/rpc 
v0.0.0-20260401024825-9d38bb4040a9/go.mod 
h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
-google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM=
-google.golang.org/grpc v1.80.0/go.mod 
h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4=
+google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 
h1:yQugLulqltosq0B/f8l4w9VryjV+N/5gcW0jQ3N8Qec=
+google.golang.org/genproto/googleapis/api 
v0.0.0-20260414002931-afd174a4e478/go.mod 
h1:C6ADNqOxbgdUUeRTU+LCHDPB9ttAMCTff6auwCVa4uc=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 
h1:RmoJA1ujG+/lRGNfUnOMfhCy5EipVMyvUE+KNbPbTlw=
+google.golang.org/genproto/googleapis/rpc 
v0.0.0-20260414002931-afd174a4e478/go.mod 
h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
+google.golang.org/grpc v1.82.1 h1:NnAxzGRA0677vCa4BUkOAnO5+FfQqVl9iUXeD0IqcGE=
+google.golang.org/grpc v1.82.1/go.mod 
h1:yzTZ1TB1Z3SG+LIYaI+WiE8D5+PZ3ArnrSp8zF3+/ZA=
 google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af 
h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI=
 google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod 
h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod 
h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helm-4.2.3/internal/release/v2/util/manifest.go 
new/helm-4.2.4/internal/release/v2/util/manifest.go
--- old/helm-4.2.3/internal/release/v2/util/manifest.go 2026-07-09 
22:15:44.000000000 +0200
+++ new/helm-4.2.4/internal/release/v2/util/manifest.go 2026-08-13 
16:46:03.000000000 +0200
@@ -34,7 +34,7 @@
        } `json:"metadata,omitempty"`
 }
 
-var sep = regexp.MustCompile("(?:^|\\s*\n)---\\s*")
+var sep = regexp.MustCompile(`(?m)^---[ \t]*`)
 
 // SplitManifests takes a manifest string and returns a map containing 
individual manifests.
 //
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helm-4.2.3/internal/release/v2/util/manifest_test.go 
new/helm-4.2.4/internal/release/v2/util/manifest_test.go
--- old/helm-4.2.3/internal/release/v2/util/manifest_test.go    2026-07-09 
22:15:44.000000000 +0200
+++ new/helm-4.2.4/internal/release/v2/util/manifest_test.go    2026-08-13 
16:46:03.000000000 +0200
@@ -73,7 +73,7 @@
                        name:  "whitespace-only doc after separator is skipped",
                        input: "---\napiVersion: v1\nkind: 
ConfigMap\nmetadata:\n  name: cm1\n---\n  \n",
                        expected: map[string]string{
-                               "manifest-0": "apiVersion: v1\nkind: 
ConfigMap\nmetadata:\n  name: cm1",
+                               "manifest-0": "apiVersion: v1\nkind: 
ConfigMap\nmetadata:\n  name: cm1\n",
                        },
                },
                {
@@ -109,7 +109,8 @@
                                "manifest-0": `apiVersion: v1
 kind: ConfigMap
 metadata:
-  name: cm1`,
+  name: cm1
+`,
                                "manifest-1": `apiVersion: v1
 kind: ConfigMap
 metadata:
@@ -328,8 +329,8 @@
                        },
                },
 
-               // Multi-doc with block scalars: the regex consumes \s*\n 
before ---,
-               // so trailing newlines from non-last docs are stripped.
+               // Multi-doc with block scalars: the separator regex preserves 
trailing
+               // newlines from non-last documents.
                {
                        name: "multi-doc block scalar clip (|) before 
separator",
                        input: `
@@ -353,7 +354,8 @@
   name: test
 data:
   key: |
-    hello`,
+    hello
+`,
                                "manifest-1": `apiVersion: v1
 kind: ConfigMap
 metadata:
@@ -386,7 +388,10 @@
   name: test
 data:
   key: |+
-    hello`,
+    hello
+
+
+`,
                                "manifest-1": `apiVersion: v1
 kind: ConfigMap
 metadata:
@@ -431,7 +436,8 @@
                                "manifest-0": `apiVersion: v1
 kind: ConfigMap
 metadata:
-  name: cm1`,
+  name: cm1
+`,
                                "manifest-1": `apiVersion: v1
 kind: ConfigMap
 metadata:
@@ -459,11 +465,13 @@
                                "manifest-0": `apiVersion: v1
 kind: ConfigMap
 metadata:
-  name: cm1`,
+  name: cm1
+`,
                                "manifest-1": `apiVersion: v1
 kind: ConfigMap
 metadata:
-  name: cm2`,
+  name: cm2
+`,
                                "manifest-2": `apiVersion: v1
 kind: ConfigMap
 metadata:
@@ -492,11 +500,13 @@
                                "manifest-0": `apiVersion: v1
 kind: ConfigMap
 metadata:
-  name: cm1`,
+  name: cm1
+`,
                                "manifest-1": `apiVersion: v1
 kind: ConfigMap
 metadata:
-  name: cm2`,
+  name: cm2
+`,
                                "manifest-2": `apiVersion: v1
 kind: ConfigMap
 metadata:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helm-4.2.3/pkg/action/action_test.go 
new/helm-4.2.4/pkg/action/action_test.go
--- old/helm-4.2.3/pkg/action/action_test.go    2026-07-09 22:15:44.000000000 
+0200
+++ new/helm-4.2.4/pkg/action/action_test.go    2026-08-13 16:46:03.000000000 
+0200
@@ -1199,9 +1199,9 @@
 `,
                },
 
-               // Multi-doc tests: block scalar doc is NOT the last document.
-               // SplitManifests' regex consumes \s*\n before ---, so trailing
-               // newlines from non-last docs are always stripped.
+               // Multi-doc block scalar tests where the block scalar document 
is NOT the last:
+               // the separator regex does not consume trailing newlines, so 
YAML chomping
+               // indicators (|, |+, |-) are respected.
 
                // | (clip) in multi-doc (first doc)
                {
@@ -1230,7 +1230,7 @@
   annotations:
     postrenderer.helm.sh/postrender-filename: 'templates/cm.yaml'
 data:
-  key: |-
+  key: |
     hello
 ---
 apiVersion: v1
@@ -1270,7 +1270,7 @@
   annotations:
     postrenderer.helm.sh/postrender-filename: 'templates/cm.yaml'
 data:
-  key: |-
+  key: |
     hello
 ---
 apiVersion: v1
@@ -1311,7 +1311,7 @@
   annotations:
     postrenderer.helm.sh/postrender-filename: 'templates/cm.yaml'
 data:
-  key: |-
+  key: |
     hello
 ---
 apiVersion: v1
@@ -1474,7 +1474,7 @@
   annotations:
     postrenderer.helm.sh/postrender-filename: 'templates/cm.yaml'
 data:
-  key: |-
+  key: |
     hello
 ---
 apiVersion: v1
@@ -1514,8 +1514,9 @@
   annotations:
     postrenderer.helm.sh/postrender-filename: 'templates/cm.yaml'
 data:
-  key: |-
+  key: |+
     hello
+
 ---
 apiVersion: v1
 kind: ConfigMap
@@ -1555,8 +1556,10 @@
   annotations:
     postrenderer.helm.sh/postrender-filename: 'templates/cm.yaml'
 data:
-  key: |-
+  key: |+
     hello
+
+
 ---
 apiVersion: v1
 kind: ConfigMap
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helm-4.2.3/pkg/action/release_testing.go 
new/helm-4.2.4/pkg/action/release_testing.go
--- old/helm-4.2.3/pkg/action/release_testing.go        2026-07-09 
22:15:44.000000000 +0200
+++ new/helm-4.2.4/pkg/action/release_testing.go        2026-08-13 
16:46:03.000000000 +0200
@@ -18,6 +18,7 @@
 
 import (
        "context"
+       "errors"
        "fmt"
        "io"
        "slices"
@@ -25,6 +26,8 @@
        "time"
 
        v1 "k8s.io/api/core/v1"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       "k8s.io/client-go/kubernetes"
 
        chartutil "helm.sh/helm/v4/pkg/chart/v2/util"
        "helm.sh/helm/v4/pkg/kube"
@@ -124,9 +127,9 @@
                return fmt.Errorf("unable to get kubernetes client to fetch pod 
logs: %w", err)
        }
 
-       hooksByWight := append([]*release.Hook{}, rel.Hooks...)
-       sort.Stable(hookByWeight(hooksByWight))
-       for _, h := range hooksByWight {
+       hooksByWeight := append([]*release.Hook{}, rel.Hooks...)
+       sort.Stable(hookByWeight(hooksByWeight))
+       for _, h := range hooksByWeight {
                for _, e := range h.Events {
                        if e == release.HookTest {
                                if 
slices.Contains(r.Filters[ExcludeNameFilter], h.Name) {
@@ -135,20 +138,43 @@
                                if len(r.Filters[IncludeNameFilter]) > 0 && 
!slices.Contains(r.Filters[IncludeNameFilter], h.Name) {
                                        continue
                                }
-                               req := 
client.CoreV1().Pods(r.Namespace).GetLogs(h.Name, &v1.PodLogOptions{})
-                               logReader, err := 
req.Stream(context.Background())
-                               if err != nil {
-                                       return fmt.Errorf("unable to get pod 
logs for %s: %w", h.Name, err)
-                               }
-
-                               fmt.Fprintf(out, "POD LOGS: %s\n", h.Name)
-                               _, err = io.Copy(out, logReader)
-                               fmt.Fprintln(out)
-                               if err != nil {
-                                       return fmt.Errorf("unable to write pod 
logs for %s: %w", h.Name, err)
+                               if err := r.getContainerLogs(out, client, 
h.Name); err != nil {
+                                       return err
                                }
                        }
                }
        }
        return nil
 }
+
+// getContainerLogs fetches logs from all containers (init and regular) in the
+// named pod and writes them to out. It continues on per-container errors and
+// returns all of them joined at the end.
+func (r *ReleaseTesting) getContainerLogs(out io.Writer, client 
kubernetes.Interface, podName string) error {
+       pod, err := client.CoreV1().Pods(r.Namespace).Get(context.Background(), 
podName, metav1.GetOptions{})
+       if err != nil {
+               return fmt.Errorf("unable to get pod %s: %w", podName, err)
+       }
+
+       allContainers := append(pod.Spec.InitContainers, pod.Spec.Containers...)
+
+       var errs []error
+       for _, c := range allContainers {
+               opts := &v1.PodLogOptions{Container: c.Name}
+               req := client.CoreV1().Pods(r.Namespace).GetLogs(podName, opts)
+               logReader, err := req.Stream(context.Background())
+               if err != nil {
+                       errs = append(errs, fmt.Errorf("unable to get logs for 
pod %s, container %s: %w", podName, c.Name, err))
+                       continue
+               }
+
+               fmt.Fprintf(out, "POD LOGS: %s (%s)\n", podName, c.Name)
+               _, err = io.Copy(out, logReader)
+               logReader.Close()
+               fmt.Fprintln(out)
+               if err != nil {
+                       errs = append(errs, fmt.Errorf("unable to write logs 
for pod %s, container %s: %w", podName, c.Name, err))
+               }
+       }
+       return errors.Join(errs...)
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helm-4.2.3/pkg/action/release_testing_test.go 
new/helm-4.2.4/pkg/action/release_testing_test.go
--- old/helm-4.2.3/pkg/action/release_testing_test.go   2026-07-09 
22:15:44.000000000 +0200
+++ new/helm-4.2.4/pkg/action/release_testing_test.go   2026-08-13 
16:46:03.000000000 +0200
@@ -26,6 +26,9 @@
 
        "github.com/stretchr/testify/assert"
        "github.com/stretchr/testify/require"
+       v1 "k8s.io/api/core/v1"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       fakeclientset "k8s.io/client-go/kubernetes/fake"
 
        "helm.sh/helm/v4/pkg/cli"
        "helm.sh/helm/v4/pkg/kube"
@@ -89,7 +92,7 @@
                },
        }
 
-       require.ErrorContains(t, client.GetPodLogs(&bytes.Buffer{}, 
&release.Release{Hooks: hooks}), "unable to get pod logs")
+       require.ErrorContains(t, client.GetPodLogs(&bytes.Buffer{}, 
&release.Release{Hooks: hooks}), "unable to get pod")
 }
 
 func TestReleaseTesting_WaitOptionsPassedDownstream(t *testing.T) {
@@ -117,3 +120,91 @@
        // Verify that WaitOptions were passed to GetWaiter
        is.NotEmpty(failer.RecordedWaitOptions, "WaitOptions should be passed 
to GetWaiter")
 }
+
+func TestGetContainerLogs_MultipleContainers(t *testing.T) {
+       pod := &v1.Pod{
+               ObjectMeta: metav1.ObjectMeta{
+                       Name:      "test-pod",
+                       Namespace: "default",
+               },
+               Spec: v1.PodSpec{
+                       Containers: []v1.Container{
+                               {Name: "main"},
+                               {Name: "sidecar"},
+                       },
+               },
+       }
+
+       client := fakeclientset.NewClientset(pod)
+       rt := &ReleaseTesting{Namespace: "default"}
+
+       var buf bytes.Buffer
+       err := rt.getContainerLogs(&buf, client, "test-pod")
+       require.NoError(t, err)
+       output := buf.String()
+       assert.Contains(t, output, "POD LOGS: test-pod (main)")
+       assert.Contains(t, output, "POD LOGS: test-pod (sidecar)")
+}
+
+func TestGetContainerLogs_WithInitContainers(t *testing.T) {
+       pod := &v1.Pod{
+               ObjectMeta: metav1.ObjectMeta{
+                       Name:      "test-pod",
+                       Namespace: "default",
+               },
+               Spec: v1.PodSpec{
+                       InitContainers: []v1.Container{
+                               {Name: "init-setup"},
+                       },
+                       Containers: []v1.Container{
+                               {Name: "main"},
+                       },
+               },
+       }
+
+       client := fakeclientset.NewClientset(pod)
+       rt := &ReleaseTesting{Namespace: "default"}
+
+       var buf bytes.Buffer
+       err := rt.getContainerLogs(&buf, client, "test-pod")
+       require.NoError(t, err)
+       output := buf.String()
+       // Init containers should appear before regular containers
+       assert.Contains(t, output, "POD LOGS: test-pod (init-setup)")
+       assert.Contains(t, output, "POD LOGS: test-pod (main)")
+}
+
+func TestGetContainerLogs_PodNotFound(t *testing.T) {
+       client := fakeclientset.NewClientset()
+       rt := &ReleaseTesting{Namespace: "default"}
+
+       var buf bytes.Buffer
+       err := rt.getContainerLogs(&buf, client, "nonexistent-pod")
+       require.Error(t, err)
+       assert.Contains(t, err.Error(), "unable to get pod nonexistent-pod")
+}
+
+func TestGetContainerLogs_OutputHeaderFormat(t *testing.T) {
+       pod := &v1.Pod{
+               ObjectMeta: metav1.ObjectMeta{
+                       Name:      "multi-test",
+                       Namespace: "default",
+               },
+               Spec: v1.PodSpec{
+                       Containers: []v1.Container{
+                               {Name: "container-a"},
+                               {Name: "container-b"},
+                       },
+               },
+       }
+
+       client := fakeclientset.NewClientset(pod)
+       rt := &ReleaseTesting{Namespace: "default"}
+
+       var buf bytes.Buffer
+       err := rt.getContainerLogs(&buf, client, "multi-test")
+       require.NoError(t, err)
+       output := buf.String()
+       assert.Contains(t, output, "POD LOGS: multi-test (container-a)")
+       assert.Contains(t, output, "POD LOGS: multi-test (container-b)")
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helm-4.2.3/pkg/action/testdata/rbac.txt 
new/helm-4.2.4/pkg/action/testdata/rbac.txt
--- old/helm-4.2.3/pkg/action/testdata/rbac.txt 2026-07-09 22:15:44.000000000 
+0200
+++ new/helm-4.2.4/pkg/action/testdata/rbac.txt 2026-08-13 16:46:03.000000000 
+0200
@@ -8,6 +8,8 @@
 - apiGroups: [""]
   resources: ["pods", "pods/exec", "pods/log"]
   verbs: ["*"]
+
+
 ---
 # Source: hello/templates/rbac
 apiVersion: rbac.authorization.k8s.io/v1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helm-4.2.3/pkg/chart/v2/util/save.go 
new/helm-4.2.4/pkg/chart/v2/util/save.go
--- old/helm-4.2.3/pkg/chart/v2/util/save.go    2026-07-09 22:15:44.000000000 
+0200
+++ new/helm-4.2.4/pkg/chart/v2/util/save.go    2026-08-13 16:46:03.000000000 
+0200
@@ -33,7 +33,11 @@
        chart "helm.sh/helm/v4/pkg/chart/v2"
 )
 
-var headerBytes = []byte("+aHR0cHM6Ly95b3V0dS5iZS96OVV6MWljandyTQo=")
+// RFC 1952 subfield header:
+// +---+---+---+---+==================================+
+// |SI1|SI2|  LEN  |... LEN bytes of subfield data ...|
+// +---+---+---+---+==================================+
+var headerBytes = []byte("rr\x28\x00aHR0cHM6Ly95b3V0dS5iZS96OVV6MWljandyTQo=")
 
 // SaveDir saves a chart as files in a directory.
 //
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helm-4.2.3/pkg/chart/v2/util/save_test.go 
new/helm-4.2.4/pkg/chart/v2/util/save_test.go
--- old/helm-4.2.3/pkg/chart/v2/util/save_test.go       2026-07-09 
22:15:44.000000000 +0200
+++ new/helm-4.2.4/pkg/chart/v2/util/save_test.go       2026-08-13 
16:46:03.000000000 +0200
@@ -21,6 +21,7 @@
        "bytes"
        "compress/gzip"
        "crypto/sha256"
+       "encoding/binary"
        "encoding/hex"
        "errors"
        "io"
@@ -35,6 +36,8 @@
        "helm.sh/helm/v4/pkg/chart/common"
        chart "helm.sh/helm/v4/pkg/chart/v2"
        "helm.sh/helm/v4/pkg/chart/v2/loader"
+
+       "github.com/stretchr/testify/require"
 )
 
 func TestSave(t *testing.T) {
@@ -130,6 +133,48 @@
        }
 }
 
+// https://github.com/helm/helm/issues/31844
+func TestSavedGzipExtraFieldIsValid(t *testing.T) {
+       tmp := t.TempDir()
+       c := &chart.Chart{
+               Metadata: &chart.Metadata{
+                       APIVersion: chart.APIVersionV2,
+                       Name:       "ahab",
+                       Version:    "1.2.3",
+               },
+       }
+
+       where, err := Save(c, tmp)
+       if err != nil {
+               t.Fatalf("Failed to save: %s", err)
+       }
+
+       f, err := os.Open(where)
+       if err != nil {
+               t.Fatalf("Failed to open saved file: %s", err)
+       }
+       defer f.Close()
+
+       r, err := gzip.NewReader(f)
+       if err != nil {
+               t.Fatalf("Failed to create gzip reader: %s", err)
+       }
+       defer r.Close()
+
+       // RFC 1952 §2.3.1.1:
+       // Each subfield consists of SI1, SI2 (1 byte each),
+       // a 2-byte little-endian LEN, and LEN bytes of data.
+       // https://www.rfc-editor.org/rfc/rfc1952.html#page-8
+       extra := r.Extra
+
+       require.NotEmpty(t, extra)
+       require.GreaterOrEqual(t, len(extra), 4)
+
+       dataLen := int(binary.LittleEndian.Uint16(extra[2:4]))
+       // Assume a single subfield.
+       require.Lenf(t, extra, 4+dataLen, "gzip extra field has malformed 
subfield: LEN=%d but %d data byte(s) follow the subfield header", dataLen, 
len(extra)-4)
+}
+
 // Creates a copy with a different schema; does not modify anything.
 func withSchema(chart chart.Chart, schema []byte) chart.Chart {
        chart.Schema = schema
@@ -299,7 +344,7 @@
                                Schema:        []byte("{\n  \"title\": 
\"Values\"\n}"),
                                SchemaModTime: modTime,
                        },
-                       want: 
"fea2662522317b65c2788ff9e5fc446a9264830038dac618d4449493d99b3257",
+                       want: 
"63358874b93ea095c857cd66bcf5d0a4464840cf84a07547db744d81d6c5af59",
                },
                {
                        name: "Package 2 files",
@@ -321,7 +366,7 @@
                                Schema:        []byte("{\n  \"title\": 
\"Values\"\n}"),
                                SchemaModTime: modTime,
                        },
-                       want: 
"7ae92b2f274bb51ea3f1969e4187d78cc52b5f6f663b44b8fb3b40bcb8ee46f3",
+                       want: 
"c2a43990053da788ad4e260d3b00d52a0b103ccc67ab9f48278a7b6dcfb2a4bd",
                },
        }
        for _, test := range tests {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helm-4.2.3/pkg/cmd/template.go 
new/helm-4.2.4/pkg/cmd/template.go
--- old/helm-4.2.3/pkg/cmd/template.go  2026-07-09 22:15:44.000000000 +0200
+++ new/helm-4.2.4/pkg/cmd/template.go  2026-08-13 16:46:03.000000000 +0200
@@ -113,6 +113,7 @@
                                }
                                return err
                        }
+                       installErr := err
 
                        // We ignore a potential error here because, when the 
--debug flag was specified,
                        // we always want to print the YAML, even if it is not 
valid. The error is still returned afterwards.
@@ -187,6 +188,10 @@
                                                        missing = false
                                                }
                                                if missing {
+                                                       if installErr != nil && 
settings.Debug {
+                                                               // assume the 
manifest itself is too malformed to be rendered
+                                                               return 
installErr
+                                                       }
                                                        return 
fmt.Errorf("could not find template %s in chart", f)
                                                }
                                        }
@@ -198,7 +203,7 @@
                                }
                        }
 
-                       return err
+                       return installErr
                },
        }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helm-4.2.3/pkg/cmd/template_test.go 
new/helm-4.2.4/pkg/cmd/template_test.go
--- old/helm-4.2.3/pkg/cmd/template_test.go     2026-07-09 22:15:44.000000000 
+0200
+++ new/helm-4.2.4/pkg/cmd/template_test.go     2026-08-13 16:46:03.000000000 
+0200
@@ -134,6 +134,12 @@
                        golden:    
"output/template-with-invalid-yaml-debug.txt",
                },
                {
+                       name:      "chart with template with invalid template 
expression (--debug, --show-only)",
+                       cmd:       fmt.Sprintf("template '%s' --debug 
--show-only %s", 
"testdata/testcharts/chart-with-template-with-invalid-template-expr", 
"templates/alpine-pod.yaml"),
+                       wantError: true,
+                       golden:    
"output/template-with-invalid-template-expr-debug-show-only.txt",
+               },
+               {
                        name:   "template skip-tests",
                        cmd:    fmt.Sprintf(`template '%s' --skip-tests`, 
chartPath),
                        golden: "output/template-skip-tests.txt",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helm-4.2.3/pkg/cmd/testdata/output/object-order.txt 
new/helm-4.2.4/pkg/cmd/testdata/output/object-order.txt
--- old/helm-4.2.3/pkg/cmd/testdata/output/object-order.txt     2026-07-09 
22:15:44.000000000 +0200
+++ new/helm-4.2.4/pkg/cmd/testdata/output/object-order.txt     2026-08-13 
16:46:03.000000000 +0200
@@ -10,6 +10,8 @@
   policyTypes:
     - Egress
     - Ingress
+
+
 ---
 # Source: object-order/templates/01-a.yml
 # 2
@@ -22,6 +24,8 @@
   policyTypes:
     - Egress
     - Ingress
+
+
 ---
 # Source: object-order/templates/01-a.yml
 # 3
@@ -34,6 +38,8 @@
   policyTypes:
     - Egress
     - Ingress
+
+
 ---
 # Source: object-order/templates/02-b.yml
 # 5
@@ -46,6 +52,8 @@
   policyTypes:
     - Egress
     - Ingress
+
+
 ---
 # Source: object-order/templates/02-b.yml
 # 7
@@ -58,6 +66,8 @@
   policyTypes:
     - Egress
     - Ingress
+
+
 ---
 # Source: object-order/templates/02-b.yml
 # 8
@@ -70,6 +80,8 @@
   policyTypes:
     - Egress
     - Ingress
+
+
 ---
 # Source: object-order/templates/02-b.yml
 # 9
@@ -82,6 +94,8 @@
   policyTypes:
     - Egress
     - Ingress
+
+
 ---
 # Source: object-order/templates/02-b.yml
 # 10
@@ -94,6 +108,8 @@
   policyTypes:
     - Egress
     - Ingress
+
+
 ---
 # Source: object-order/templates/02-b.yml
 # 11
@@ -106,6 +122,8 @@
   policyTypes:
     - Egress
     - Ingress
+
+
 ---
 # Source: object-order/templates/02-b.yml
 # 12
@@ -118,6 +136,8 @@
   policyTypes:
     - Egress
     - Ingress
+
+
 ---
 # Source: object-order/templates/02-b.yml
 # 13
@@ -130,6 +150,8 @@
   policyTypes:
     - Egress
     - Ingress
+
+
 ---
 # Source: object-order/templates/02-b.yml
 # 14
@@ -142,6 +164,8 @@
   policyTypes:
     - Egress
     - Ingress
+
+
 ---
 # Source: object-order/templates/02-b.yml
 # 15 (11th object within 02-b.yml, in order to test `SplitManifests` which 
assigns `manifest-10`
@@ -190,3 +214,5 @@
   policyTypes:
     - Egress
     - Ingress
+
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/helm-4.2.3/pkg/cmd/testdata/output/template-show-only-glob.txt 
new/helm-4.2.4/pkg/cmd/testdata/output/template-show-only-glob.txt
--- old/helm-4.2.3/pkg/cmd/testdata/output/template-show-only-glob.txt  
2026-07-09 22:15:44.000000000 +0200
+++ new/helm-4.2.4/pkg/cmd/testdata/output/template-show-only-glob.txt  
2026-08-13 16:46:03.000000000 +0200
@@ -8,6 +8,8 @@
 - apiGroups: [""]
   resources: ["pods"]
   verbs: ["get","list","watch"]
+
+
 ---
 # Source: subchart/templates/subdir/rolebinding.yaml
 apiVersion: rbac.authorization.k8s.io/v1
@@ -22,3 +24,5 @@
 - kind: ServiceAccount
   name: subchart-sa
   namespace: default
+
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/helm-4.2.3/pkg/cmd/testdata/output/template-show-only-multiple.txt 
new/helm-4.2.4/pkg/cmd/testdata/output/template-show-only-multiple.txt
--- old/helm-4.2.3/pkg/cmd/testdata/output/template-show-only-multiple.txt      
2026-07-09 22:15:44.000000000 +0200
+++ new/helm-4.2.4/pkg/cmd/testdata/output/template-show-only-multiple.txt      
2026-08-13 16:46:03.000000000 +0200
@@ -19,6 +19,7 @@
     name: nginx
   selector:
     app.kubernetes.io/name: subchart
+
 ---
 # Source: subchart/charts/subcharta/templates/service.yaml
 apiVersion: v1
@@ -36,3 +37,5 @@
     name: apache
   selector:
     app.kubernetes.io/name: subcharta
+
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/helm-4.2.3/pkg/cmd/testdata/output/template-show-only-one.txt 
new/helm-4.2.4/pkg/cmd/testdata/output/template-show-only-one.txt
--- old/helm-4.2.3/pkg/cmd/testdata/output/template-show-only-one.txt   
2026-07-09 22:15:44.000000000 +0200
+++ new/helm-4.2.4/pkg/cmd/testdata/output/template-show-only-one.txt   
2026-08-13 16:46:03.000000000 +0200
@@ -19,3 +19,4 @@
     name: nginx
   selector:
     app.kubernetes.io/name: subchart
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/helm-4.2.3/pkg/cmd/testdata/output/template-with-invalid-template-expr-debug-show-only.txt
 
new/helm-4.2.4/pkg/cmd/testdata/output/template-with-invalid-template-expr-debug-show-only.txt
--- 
old/helm-4.2.3/pkg/cmd/testdata/output/template-with-invalid-template-expr-debug-show-only.txt
      1970-01-01 01:00:00.000000000 +0100
+++ 
new/helm-4.2.4/pkg/cmd/testdata/output/template-with-invalid-template-expr-debug-show-only.txt
      2026-08-13 16:46:03.000000000 +0200
@@ -0,0 +1,3 @@
+Error: 
chart-with-template-with-invalid-template-expr/templates/alpine-pod.yaml:7:38
+  executing 
"chart-with-template-with-invalid-template-expr/templates/alpine-pod.yaml" at 
<b64enc>:
+    invalid value; expected string
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/helm-4.2.3/pkg/cmd/testdata/testcharts/chart-with-template-with-invalid-template-expr/Chart.yaml
 
new/helm-4.2.4/pkg/cmd/testdata/testcharts/chart-with-template-with-invalid-template-expr/Chart.yaml
--- 
old/helm-4.2.3/pkg/cmd/testdata/testcharts/chart-with-template-with-invalid-template-expr/Chart.yaml
        1970-01-01 01:00:00.000000000 +0100
+++ 
new/helm-4.2.4/pkg/cmd/testdata/testcharts/chart-with-template-with-invalid-template-expr/Chart.yaml
        2026-08-13 16:46:03.000000000 +0200
@@ -0,0 +1,8 @@
+apiVersion: v1
+description: Deploy a basic Alpine Linux pod
+home: https://helm.sh/helm
+name: chart-with-template-with-invalid-template-expr
+sources:
+  - https://github.com/helm/helm
+version: 0.1.0
+type: application
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/helm-4.2.3/pkg/cmd/testdata/testcharts/chart-with-template-with-invalid-template-expr/README.md
 
new/helm-4.2.4/pkg/cmd/testdata/testcharts/chart-with-template-with-invalid-template-expr/README.md
--- 
old/helm-4.2.3/pkg/cmd/testdata/testcharts/chart-with-template-with-invalid-template-expr/README.md
 1970-01-01 01:00:00.000000000 +0100
+++ 
new/helm-4.2.4/pkg/cmd/testdata/testcharts/chart-with-template-with-invalid-template-expr/README.md
 2026-08-13 16:46:03.000000000 +0200
@@ -0,0 +1,13 @@
+#Alpine: A simple Helm chart
+
+Run a single pod of Alpine Linux.
+
+This example was generated using the command `helm create alpine`.
+
+The `templates/` directory contains a very simple pod resource with a
+couple of parameters.
+
+The `values.yaml` file contains the default values for the
+`alpine-pod.yaml` template.
+
+You can install this example using `helm install ./alpine`.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/helm-4.2.3/pkg/cmd/testdata/testcharts/chart-with-template-with-invalid-template-expr/templates/alpine-pod.yaml
 
new/helm-4.2.4/pkg/cmd/testdata/testcharts/chart-with-template-with-invalid-template-expr/templates/alpine-pod.yaml
--- 
old/helm-4.2.3/pkg/cmd/testdata/testcharts/chart-with-template-with-invalid-template-expr/templates/alpine-pod.yaml
 1970-01-01 01:00:00.000000000 +0100
+++ 
new/helm-4.2.4/pkg/cmd/testdata/testcharts/chart-with-template-with-invalid-template-expr/templates/alpine-pod.yaml
 2026-08-13 16:46:03.000000000 +0200
@@ -0,0 +1,9 @@
+apiVersion: v1
+kind: Pod
+metadata:
+  name: "{{.Release.Name}}-{{.Values.Name}}"
+spec:
+  containers:
+  - name: {{ .Values.nonExistentKey | b64enc }}
+    image: "alpine:3.9"
+    command: ["/bin/sleep","9000"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/helm-4.2.3/pkg/cmd/testdata/testcharts/chart-with-template-with-invalid-template-expr/values.yaml
 
new/helm-4.2.4/pkg/cmd/testdata/testcharts/chart-with-template-with-invalid-template-expr/values.yaml
--- 
old/helm-4.2.3/pkg/cmd/testdata/testcharts/chart-with-template-with-invalid-template-expr/values.yaml
       1970-01-01 01:00:00.000000000 +0100
+++ 
new/helm-4.2.4/pkg/cmd/testdata/testcharts/chart-with-template-with-invalid-template-expr/values.yaml
       2026-08-13 16:46:03.000000000 +0200
@@ -0,0 +1 @@
+Name: my-alpine
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helm-4.2.3/pkg/cmd/upgrade.go 
new/helm-4.2.4/pkg/cmd/upgrade.go
--- old/helm-4.2.3/pkg/cmd/upgrade.go   2026-07-09 22:15:44.000000000 +0200
+++ new/helm-4.2.4/pkg/cmd/upgrade.go   2026-08-13 16:46:03.000000000 +0200
@@ -217,6 +217,7 @@
                                                        RepositoryCache:  
settings.RepositoryCache,
                                                        ContentCache:     
settings.ContentCache,
                                                        Debug:            
settings.Debug,
+                                                       RegistryClient:   
registryClient,
                                                }
                                                if err := man.Update(); err != 
nil {
                                                        return err
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helm-4.2.3/pkg/cmd/upgrade_test.go 
new/helm-4.2.4/pkg/cmd/upgrade_test.go
--- old/helm-4.2.3/pkg/cmd/upgrade_test.go      2026-07-09 22:15:44.000000000 
+0200
+++ new/helm-4.2.4/pkg/cmd/upgrade_test.go      2026-08-13 16:46:03.000000000 
+0200
@@ -18,6 +18,8 @@
 
 import (
        "fmt"
+       "net/http"
+       "net/http/httptest"
        "os"
        "path/filepath"
        "reflect"
@@ -194,6 +196,64 @@
        runTestCmd(t, tests)
 }
 
+// TestUpgradeDependencyUpdateOCINoPanic is a regression test for a nil-pointer
+// panic in `helm upgrade --dependency-update` when a chart declares an OCI
+// dependency. The upgrade command built its downloader.Manager without a
+// RegistryClient (unlike install, dependency update, and dependency build), so
+// resolving an OCI dependency dereferenced a nil *registry.Client. The command
+// must now return a graceful error instead of panicking.
+func TestUpgradeDependencyUpdateOCINoPanic(t *testing.T) {
+       defer resetEnv()()
+
+       // A stub registry that answers the API-version ping but rejects the tag
+       // lookup, so OCI dependency resolution fails fast and hermetically 
instead
+       // of reaching a real registry.
+       srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, 
r *http.Request) {
+               w.Header().Set("Docker-Distribution-API-Version", 
"registry/2.0")
+               if r.URL.Path == "/v2/" {
+                       w.WriteHeader(http.StatusOK)
+                       return
+               }
+               w.WriteHeader(http.StatusNotFound)
+       }))
+       defer srv.Close()
+
+       // A chart with an unresolved OCI dependency forces --dependency-update 
into
+       // the tag-lookup path that previously panicked: the version is a range 
(an
+       // explicit version would skip the lookup) and the dependency is not 
present
+       // under charts/.
+       tmp := t.TempDir()
+       parent := &chart.Chart{
+               Metadata: &chart.Metadata{
+                       APIVersion: chart.APIVersionV2,
+                       Name:       "oci-parent",
+                       Version:    "0.1.0",
+                       Dependencies: []*chart.Dependency{{
+                               Name:       "subchart",
+                               Repository: fmt.Sprintf("oci://%s/charts", 
srv.Listener.Addr()),
+                               Version:    "^1.0.0",
+                       }},
+               },
+       }
+       if err := chartutil.SaveDir(parent, tmp); err != nil {
+               t.Fatalf("Error creating chart: %v", err)
+       }
+       chartPath := filepath.Join(tmp, parent.Metadata.Name)
+       // SaveDir writes only resolved subcharts (Chart.Dependencies()), not 
the
+       // declared Metadata.Dependencies, so create the empty charts/ directory
+       // explicitly to make the "dependency missing from charts/" state 
concrete.
+       if err := os.MkdirAll(filepath.Join(chartPath, "charts"), 0o755); err 
!= nil {
+               t.Fatalf("Error creating charts dir: %v", err)
+       }
+
+       // The command must return an error (registry rejects the lookup), not 
panic.
+       _, _, err := executeActionCommandC(storageFixture(),
+               fmt.Sprintf("upgrade --dependency-update --plain-http 
oci-parent '%s'", chartPath))
+       if err == nil {
+               t.Fatal("expected an error resolving the OCI dependency, got 
nil")
+       }
+}
+
 func TestUpgradeWithValue(t *testing.T) {
        releaseName := "funny-bunny-v2"
        relMock, ch, chartPath := prepareMockRelease(t, releaseName)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helm-4.2.3/pkg/kube/client.go 
new/helm-4.2.4/pkg/kube/client.go
--- old/helm-4.2.3/pkg/kube/client.go   2026-07-09 22:15:44.000000000 +0200
+++ new/helm-4.2.4/pkg/kube/client.go   2026-08-13 16:46:03.000000000 +0200
@@ -235,12 +235,15 @@
 
 // getKubeClient get or create a new KubernetesClientSet
 func (c *Client) getKubeClient() (kubernetes.Interface, error) {
-       var err error
-       if c.kubeClient == nil {
-               c.kubeClient, err = c.Factory.KubernetesClientSet()
+       if c.kubeClient != nil {
+               return c.kubeClient, nil
        }
-
-       return c.kubeClient, err
+       kc, err := c.Factory.KubernetesClientSet()
+       if err != nil {
+               return nil, err
+       }
+       c.kubeClient = kc
+       return c.kubeClient, nil
 }
 
 // IsReachable tests connectivity to the cluster.
@@ -318,20 +321,24 @@
                        slog.String("fieldValidationDirective", 
string(fieldValidationDirective)))
 
                return func(target *resource.Info) error {
-                       err := patchResourceServerSide(target, dryRun, 
forceConflicts, fieldValidationDirective)
-
                        logger := c.Logger().With(
                                slog.String("namespace", target.Namespace),
                                slog.String("name", target.Name),
                                slog.String("gvk", 
target.Mapping.GroupVersionKind.String()))
-                       if err != nil {
-                               logger.Debug("Error creating resource via 
patch", slog.Any("error", err))
-                               return err
-                       }
 
-                       logger.Debug("Created resource via patch")
+                       return retry.OnError(
+                               retry.DefaultRetry,
+                               isServerSideRetryable,
+                               func() error {
+                                       err := patchResourceServerSide(target, 
dryRun, forceConflicts, fieldValidationDirective)
+                                       if err != nil {
+                                               logger.Debug("Error creating 
resource via patch", slog.Any("error", err))
+                                               return err
+                                       }
 
-                       return nil
+                                       logger.Debug("Created resource via 
patch")
+                                       return nil
+                               })
                }
        }
 
@@ -951,6 +958,32 @@
        return err.(*apierrors.StatusError).Status().Code == 
http.StatusUnsupportedMediaType
 }
 
+// isServerSideRetryable checks if an error encountered during server-side 
apply
+// should be retried. Currently, only ResourceQuota conflicts are considered 
retryable.
+func isServerSideRetryable(err error) bool {
+       return isResourceQuotaConflict(err)
+}
+
+// isResourceQuotaConflict checks if the error is a conflict error 
specifically caused by
+// a ResourceQuota. This is used to determine if a retry should be attempted,
+// since quota conflicts are typically transient and can be resolved by 
retrying.
+func isResourceQuotaConflict(err error) bool {
+       if !apierrors.IsConflict(err) {
+               return false
+       }
+
+       // Check the error message for the specific ResourceQuota conflict 
pattern.
+       // The error message from the ResourceQuota admission controller 
contains:
+       // "Operation cannot be fulfilled on resourcequotas" and "the object 
has been modified"
+       errMsg := err.Error()
+       if strings.Contains(errMsg, "Operation cannot be fulfilled on 
resourcequotas") &&
+               strings.Contains(errMsg, "the object has been modified") {
+               return true
+       }
+
+       return false
+}
+
 // getManagedFieldsManager returns the manager string. If one was set it will 
be returned.
 // Otherwise, one is calculated based on the name of the binary.
 func getManagedFieldsManager() string {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helm-4.2.3/pkg/kube/client_test.go 
new/helm-4.2.4/pkg/kube/client_test.go
--- old/helm-4.2.3/pkg/kube/client_test.go      2026-07-09 22:15:44.000000000 
+0200
+++ new/helm-4.2.4/pkg/kube/client_test.go      2026-08-13 16:46:03.000000000 
+0200
@@ -53,6 +53,7 @@
        k8sfake "k8s.io/client-go/kubernetes/fake"
        "k8s.io/client-go/kubernetes/scheme"
        "k8s.io/client-go/rest/fake"
+       "k8s.io/client-go/util/retry"
        cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
 )
 
@@ -273,8 +274,30 @@
                        },
                        ExpectedErrorContains: "Operation cannot be fulfilled 
on resourcequotas \"quota\": the object has been modified; " +
                                "please apply your changes to the latest 
version and try again",
+                       ExpectedActions: func() []string { // expect helm to 
retry on conflict, workaround for: 
https://github.com/kubernetes/kubernetes/issues/67761
+                               actions := make([]string, 
retry.DefaultRetry.Steps)
+                               for i := range actions {
+                                       actions[i] = 
"/namespaces/default/pods/dolphin:PATCH"
+                               }
+                               return actions
+                       }(),
+               },
+               "Create fail: managed fields conflict (server-side apply)": {
+                       Pods:            newPodList("seal"),
+                       ServerSideApply: true,
+                       Callback: func(t *testing.T, _ testCase, _ 
[]RequestResponseAction, req *http.Request) (*http.Response, error) {
+                               t.Helper()
+
+                               // Return a generic 409 conflict (not 
quota-related)
+                               // This simulates a managed fields conflict
+                               return &http.Response{
+                                       StatusCode: http.StatusConflict,
+                                       Request:    req,
+                               }, nil
+                       },
+                       ExpectedErrorContains: "the server reported a conflict",
                        ExpectedActions: []string{
-                               "/namespaces/default/pods/dolphin:PATCH",
+                               "/namespaces/default/pods/seal:PATCH",
                        },
                },
        }
@@ -1420,6 +1443,26 @@
        }
 }
 
+func TestIsReachableTwiceAfterClientCreationFailure(t *testing.T) {
+       refusedErr := errors.New("connection refused")
+       client := newTestClient(t)
+       client.Factory = &errorFactory{err: refusedErr}
+
+       assertReachableErr := func(label string, err error) {
+               t.Helper()
+               if err == nil {
+                       t.Fatalf("%s: expected error, got nil", label)
+               }
+               if !errors.Is(err, refusedErr) {
+                       t.Fatalf("%s: expected error wrapping %v, got %v", 
label, refusedErr, err)
+               }
+       }
+
+       assertReachableErr("first call", client.IsReachable())
+       // Second call must return the same underlying error, not panic.
+       assertReachableErr("second call", client.IsReachable())
+}
+
 func TestIsIncompatibleServerError(t *testing.T) {
        testCases := map[string]struct {
                Err  error
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helm-4.2.3/pkg/provenance/sign.go 
new/helm-4.2.4/pkg/provenance/sign.go
--- old/helm-4.2.3/pkg/provenance/sign.go       2026-07-09 22:15:44.000000000 
+0200
+++ new/helm-4.2.4/pkg/provenance/sign.go       2026-08-13 16:46:03.000000000 
+0200
@@ -388,7 +388,7 @@
 func Digest(in io.Reader) (string, error) {
        hash := crypto.SHA256.New()
        if _, err := io.Copy(hash, in); err != nil {
-               return "", nil
+               return "", err
        }
        return hex.EncodeToString(hash.Sum(nil)), nil
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helm-4.2.3/pkg/registry/client.go 
new/helm-4.2.4/pkg/registry/client.go
--- old/helm-4.2.3/pkg/registry/client.go       2026-07-09 22:15:44.000000000 
+0200
+++ new/helm-4.2.4/pkg/registry/client.go       2026-08-13 16:46:03.000000000 
+0200
@@ -717,6 +717,8 @@
        repository.PlainHTTP = c.plainHTTP
        repository.Client = c.authorizer
 
+       ctx = withScopeHint(ctx, repository, auth.ActionPull, auth.ActionPush)
+
        manifestDescriptor, err = oras.ExtendedCopy(ctx, memoryStore, 
parsedRef.String(), repository, parsedRef.String(), 
oras.DefaultExtendedCopyOptions)
        if err != nil {
                return nil, err
@@ -929,3 +931,14 @@
        return oras.TagBytes(ctx, memoryStore, ocispec.MediaTypeImageManifest,
                manifestData, parsedRef.String())
 }
+
+// add actions when request a registry authentication token(jwt)
+// example1. when we want to pull 'testrepo/local-subchart' we can send below 
url, and 'pull' is the action
+// auth?scope=repository%3Atestrepo%2Flocal-subchart%3Apull&service=testservice
+// example2. when we want to push 'testrepo/local-subchart' we can send below 
url, and 'pull%2Cpush' are the actions
+// 
auth?scope=repository%3Atestrepo%2Flocal-subchart%3Apull%2Cpush&service=testservice
+// we can set the actions like below
+// example) ctx = withScopeHint(ctx, repository, auth.ActionPush, 
auth.ActionPull)
+func withScopeHint(ctx context.Context, repo *remote.Repository, actions 
...string) context.Context {
+       return auth.AppendRepositoryScope(ctx, repo.Reference, actions...)
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helm-4.2.3/pkg/registry/client_http_test.go 
new/helm-4.2.4/pkg/registry/client_http_test.go
--- old/helm-4.2.3/pkg/registry/client_http_test.go     2026-07-09 
22:15:44.000000000 +0200
+++ new/helm-4.2.4/pkg/registry/client_http_test.go     2026-08-13 
16:46:03.000000000 +0200
@@ -31,7 +31,7 @@
 
 func (suite *HTTPRegistryClientTestSuite) SetupSuite() {
        // init test client
-       setup(&suite.TestRegistry, false, false)
+       setup(&suite.TestRegistry, false, false, "htpasswd")
 }
 
 func (suite *HTTPRegistryClientTestSuite) TearDownSuite() {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helm-4.2.3/pkg/registry/client_insecure_tls_test.go 
new/helm-4.2.4/pkg/registry/client_insecure_tls_test.go
--- old/helm-4.2.3/pkg/registry/client_insecure_tls_test.go     2026-07-09 
22:15:44.000000000 +0200
+++ new/helm-4.2.4/pkg/registry/client_insecure_tls_test.go     2026-08-13 
16:46:03.000000000 +0200
@@ -29,7 +29,7 @@
 
 func (suite *InsecureTLSRegistryClientTestSuite) SetupSuite() {
        // init test client
-       setup(&suite.TestRegistry, true, true)
+       setup(&suite.TestRegistry, true, true, "htpasswd")
 }
 
 func (suite *InsecureTLSRegistryClientTestSuite) TearDownSuite() {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helm-4.2.3/pkg/registry/client_scope_test.go 
new/helm-4.2.4/pkg/registry/client_scope_test.go
--- old/helm-4.2.3/pkg/registry/client_scope_test.go    1970-01-01 
01:00:00.000000000 +0100
+++ new/helm-4.2.4/pkg/registry/client_scope_test.go    2026-08-13 
16:46:03.000000000 +0200
@@ -0,0 +1,142 @@
+/*
+Copyright The Helm Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package registry
+
+import (
+       "fmt"
+       "net"
+       "net/http"
+       "net/http/httptest"
+       "net/url"
+       "os"
+       "testing"
+       "time"
+
+       "github.com/stretchr/testify/suite"
+)
+
+type RegistryScopeTestSuite struct {
+       TestRegistry
+}
+
+func (suite *RegistryScopeTestSuite) SetupSuite() {
+       // Set up a plain-HTTP registry that uses token auth. The token realm is
+       // served over http (see setup), so the registry must be contacted over
+       // http as well: oras refuses to send credentials to an http token realm
+       // when the registry itself was reached over https.
+       setup(&suite.TestRegistry, false, false, "token")
+}
+func (suite *RegistryScopeTestSuite) TearDownSuite() {
+       teardown(&suite.TestRegistry)
+       os.RemoveAll(suite.WorkspaceDir)
+}
+
+func (suite *RegistryScopeTestSuite) Test_1_Check_Push_Request_Scope() {
+       requestURL := make(chan string, 1)
+       handler := http.HandlerFunc(func(w http.ResponseWriter, r 
*http.Request) {
+               // Capture only the first auth request; never block the handler 
if the
+               // client happens to retry, so the auth server always responds 
and the
+               // push/pull flow can't deadlock waiting on us.
+               select {
+               case requestURL <- r.URL.String():
+               default:
+               }
+               w.WriteHeader(http.StatusOK)
+       })
+       lnCfg := net.ListenConfig{}
+       listener, err := lnCfg.Listen(suite.T().Context(), "tcp", 
suite.AuthServerHost)
+       suite.NoError(err, "no error creating server listener")
+
+       ts := httptest.NewUnstartedServer(handler)
+       ts.Listener = listener
+       ts.Start()
+       defer ts.Close()
+
+       // basic push, good ref
+       testingChartCreationTime := "1977-09-02T22:04:05Z"
+       chartData, err := 
os.ReadFile("../downloader/testdata/local-subchart-0.1.0.tgz")
+       suite.NoError(err, "no error loading test chart")
+       meta, err := extractChartMeta(chartData)
+       suite.NoError(err, "no error extracting chart meta")
+       ref := fmt.Sprintf("%s/testrepo/%s:%s", suite.DockerRegistryHost, 
meta.Name, meta.Version)
+       _, err = suite.RegistryClient.Push(chartData, ref, 
PushOptCreationTime(testingChartCreationTime))
+       suite.Error(err, "error pushing good ref because auth server doesn't 
give proper token")
+
+       //check the url that authentication server received
+       select {
+       case urlStr := <-requestURL:
+               u, err := url.Parse(urlStr)
+               suite.NoError(err, "no error parsing requested URL")
+
+               suite.Equal("/auth", u.Path)
+               suite.Equal("testservice", u.Query().Get("service"))
+               scope := u.Query().Get("scope")
+               suite.Contains(scope, 
"repository:testrepo/local-subchart:pull,push")
+       case <-time.After(5 * time.Second):
+               suite.T().Fatal("timeout waiting for auth request")
+       }
+}
+
+func (suite *RegistryScopeTestSuite) Test_2_Check_Pull_Request_Scope() {
+       requestURL := make(chan string, 1)
+       handler := http.HandlerFunc(func(w http.ResponseWriter, r 
*http.Request) {
+               // Capture only the first auth request; never block the handler 
if the
+               // client happens to retry, so the auth server always responds 
and the
+               // push/pull flow can't deadlock waiting on us.
+               select {
+               case requestURL <- r.URL.String():
+               default:
+               }
+               w.WriteHeader(http.StatusOK)
+       })
+       lnCfg := net.ListenConfig{}
+       listener, err := lnCfg.Listen(suite.T().Context(), "tcp", 
suite.AuthServerHost)
+       suite.NoError(err, "no error creating server listener")
+
+       ts := httptest.NewUnstartedServer(handler)
+       ts.Listener = listener
+       ts.Start()
+       defer ts.Close()
+
+       // Load test chart (to build ref pushed in previous test)
+       // Simple pull, chart only
+       chartData, err := 
os.ReadFile("../downloader/testdata/local-subchart-0.1.0.tgz")
+       suite.NoError(err, "no error loading test chart")
+       meta, err := extractChartMeta(chartData)
+       suite.NoError(err, "no error extracting chart meta")
+       ref := fmt.Sprintf("%s/testrepo/%s:%s", suite.DockerRegistryHost, 
meta.Name, meta.Version)
+       _, err = suite.RegistryClient.Pull(ref)
+       suite.Error(err, "error pulling a simple chart because auth server 
doesn't give proper token")
+
+       //check the url that authentication server received
+       select {
+       case urlStr := <-requestURL:
+               u, err := url.Parse(urlStr)
+               suite.NoError(err, "no error parsing requested URL")
+
+               suite.Equal("/auth", u.Path)
+               suite.Equal("testservice", u.Query().Get("service"))
+               scope := u.Query().Get("scope")
+               suite.Contains(scope, "repository:testrepo/local-subchart:pull")
+       case <-time.After(5 * time.Second):
+               suite.T().Fatal("timeout waiting for auth request")
+       }
+}
+
+func TestRegistryScopeTestSuite(t *testing.T) {
+       suite.Run(t, new(RegistryScopeTestSuite))
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helm-4.2.3/pkg/registry/client_tls_test.go 
new/helm-4.2.4/pkg/registry/client_tls_test.go
--- old/helm-4.2.3/pkg/registry/client_tls_test.go      2026-07-09 
22:15:44.000000000 +0200
+++ new/helm-4.2.4/pkg/registry/client_tls_test.go      2026-08-13 
16:46:03.000000000 +0200
@@ -31,7 +31,7 @@
 
 func (suite *TLSRegistryClientTestSuite) SetupSuite() {
        // init test client
-       setup(&suite.TestRegistry, true, false)
+       setup(&suite.TestRegistry, true, false, "htpasswd")
 }
 
 func (suite *TLSRegistryClientTestSuite) TearDownSuite() {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helm-4.2.3/pkg/registry/registry_test.go 
new/helm-4.2.4/pkg/registry/registry_test.go
--- old/helm-4.2.3/pkg/registry/registry_test.go        2026-07-09 
22:15:44.000000000 +0200
+++ new/helm-4.2.4/pkg/registry/registry_test.go        2026-08-13 
16:46:03.000000000 +0200
@@ -34,6 +34,7 @@
        "github.com/distribution/distribution/v3/configuration"
        "github.com/distribution/distribution/v3/registry"
        _ "github.com/distribution/distribution/v3/registry/auth/htpasswd"
+       _ "github.com/distribution/distribution/v3/registry/auth/token"
        _ 
"github.com/distribution/distribution/v3/registry/storage/driver/inmemory"
        ocispec "github.com/opencontainers/image-spec/specs-go/v1"
        "github.com/stretchr/testify/require"
@@ -56,6 +57,8 @@
        testHtpasswdFileBasename = "authtest.htpasswd"
        testUsername             = "myuser"
        testPassword             = "mypass"
+       testIssuer               = "testissuer"
+       testService              = "testservice"
 )
 
 type TestRegistry struct {
@@ -63,13 +66,14 @@
        Out                     io.Writer
        FakeRegistryHost        string
        DockerRegistryHost      string
+       AuthServerHost          string
        CompromisedRegistryHost string
        WorkspaceDir            string
        RegistryClient          *Client
        dockerRegistry          *registry.Registry
 }
 
-func setup(suite *TestRegistry, tlsEnabled, insecure bool) {
+func setup(suite *TestRegistry, tlsEnabled, insecure bool, auth string) {
        suite.WorkspaceDir = testWorkspaceDir
        err := os.RemoveAll(suite.WorkspaceDir)
        require.NoError(suite.T(), err, "no error removing test workspace dir")
@@ -125,25 +129,47 @@
 
        // Registry config
        config := &configuration.Configuration{}
+       lnCfg := net.ListenConfig{}
        ln, err := net.Listen("tcp", "127.0.0.1:0")
        suite.Nil(err, "no error finding free port for test registry")
        defer func() { _ = ln.Close() }()
 
-       // Change the registry host to another host which is not localhost.
-       // This is required because Docker enforces HTTP if the registry
-       // host is localhost/127.0.0.1.
+       // Use localhost for HTTP tests and helm-test-registry for TLS tests.
+       // TLS tests need a different hostname to match the certificate.
        port := ln.Addr().(*net.TCPAddr).Port
-       suite.DockerRegistryHost = fmt.Sprintf("helm-test-registry:%d", port)
+       if tlsEnabled {
+               suite.DockerRegistryHost = fmt.Sprintf("helm-test-registry:%d", 
port)
+       } else {
+               suite.DockerRegistryHost = fmt.Sprintf("127.0.0.1:%d", port)
+       }
 
        config.HTTP.Addr = ln.Addr().String()
        config.HTTP.DrainTimeout = time.Duration(10) * time.Second
        config.Storage = map[string]configuration.Parameters{"inmemory": 
map[string]any{}}
 
-       config.Auth = configuration.Auth{
-               "htpasswd": configuration.Parameters{
-                       "realm": "localhost",
-                       "path":  htpasswdPath,
-               },
+       if auth == "token" {
+               ln, err := lnCfg.Listen(suite.T().Context(), "tcp", 
"127.0.0.1:0")
+               suite.Require().NoError(err, "no error finding free port for 
test auth server")
+               defer ln.Close()
+
+               //set test auth server host
+               suite.AuthServerHost = ln.Addr().String()
+
+               config.Auth = configuration.Auth{
+                       "token": configuration.Parameters{
+                               "realm":          "http://"; + 
suite.AuthServerHost + "/auth",
+                               "service":        testService,
+                               "issuer":         testIssuer,
+                               "rootcertbundle": tlsServerCert,
+                       },
+               }
+       } else {
+               config.Auth = configuration.Auth{
+                       "htpasswd": configuration.Parameters{
+                               "realm": "localhost",
+                               "path":  htpasswdPath,
+                       },
+               }
        }
 
        // config tls
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helm-4.2.3/pkg/release/v1/util/manifest.go 
new/helm-4.2.4/pkg/release/v1/util/manifest.go
--- old/helm-4.2.3/pkg/release/v1/util/manifest.go      2026-07-09 
22:15:44.000000000 +0200
+++ new/helm-4.2.4/pkg/release/v1/util/manifest.go      2026-08-13 
16:46:03.000000000 +0200
@@ -34,7 +34,7 @@
        } `json:"metadata,omitempty"`
 }
 
-var sep = regexp.MustCompile("(?:^|\\s*\n)---\\s*")
+var sep = regexp.MustCompile(`(?m)^---[ \t]*`)
 
 // SplitManifests takes a manifest string and returns a map containing 
individual manifests.
 //
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helm-4.2.3/pkg/release/v1/util/manifest_test.go 
new/helm-4.2.4/pkg/release/v1/util/manifest_test.go
--- old/helm-4.2.3/pkg/release/v1/util/manifest_test.go 2026-07-09 
22:15:44.000000000 +0200
+++ new/helm-4.2.4/pkg/release/v1/util/manifest_test.go 2026-08-13 
16:46:03.000000000 +0200
@@ -73,7 +73,7 @@
                        name:  "whitespace-only doc after separator is skipped",
                        input: "---\napiVersion: v1\nkind: 
ConfigMap\nmetadata:\n  name: cm1\n---\n  \n",
                        expected: map[string]string{
-                               "manifest-0": "apiVersion: v1\nkind: 
ConfigMap\nmetadata:\n  name: cm1",
+                               "manifest-0": "apiVersion: v1\nkind: 
ConfigMap\nmetadata:\n  name: cm1\n",
                        },
                },
                {
@@ -109,7 +109,8 @@
                                "manifest-0": `apiVersion: v1
 kind: ConfigMap
 metadata:
-  name: cm1`,
+  name: cm1
+`,
                                "manifest-1": `apiVersion: v1
 kind: ConfigMap
 metadata:
@@ -328,8 +329,8 @@
                        },
                },
 
-               // Multi-doc with block scalars: the regex consumes \s*\n 
before ---,
-               // so trailing newlines from non-last docs are stripped.
+               // Multi-doc with block scalars: the separator regex preserves 
trailing
+               // newlines from non-last documents.
                {
                        name: "multi-doc block scalar clip (|) before 
separator",
                        input: `
@@ -353,7 +354,8 @@
   name: test
 data:
   key: |
-    hello`,
+    hello
+`,
                                "manifest-1": `apiVersion: v1
 kind: ConfigMap
 metadata:
@@ -386,7 +388,10 @@
   name: test
 data:
   key: |+
-    hello`,
+    hello
+
+
+`,
                                "manifest-1": `apiVersion: v1
 kind: ConfigMap
 metadata:
@@ -431,7 +436,8 @@
                                "manifest-0": `apiVersion: v1
 kind: ConfigMap
 metadata:
-  name: cm1`,
+  name: cm1
+`,
                                "manifest-1": `apiVersion: v1
 kind: ConfigMap
 metadata:
@@ -459,11 +465,13 @@
                                "manifest-0": `apiVersion: v1
 kind: ConfigMap
 metadata:
-  name: cm1`,
+  name: cm1
+`,
                                "manifest-1": `apiVersion: v1
 kind: ConfigMap
 metadata:
-  name: cm2`,
+  name: cm2
+`,
                                "manifest-2": `apiVersion: v1
 kind: ConfigMap
 metadata:
@@ -492,11 +500,13 @@
                                "manifest-0": `apiVersion: v1
 kind: ConfigMap
 metadata:
-  name: cm1`,
+  name: cm1
+`,
                                "manifest-1": `apiVersion: v1
 kind: ConfigMap
 metadata:
-  name: cm2`,
+  name: cm2
+`,
                                "manifest-2": `apiVersion: v1
 kind: ConfigMap
 metadata:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/helm-4.2.3/pkg/storage/driver/util.go 
new/helm-4.2.4/pkg/storage/driver/util.go
--- old/helm-4.2.3/pkg/storage/driver/util.go   2026-07-09 22:15:44.000000000 
+0200
+++ new/helm-4.2.4/pkg/storage/driver/util.go   2026-08-13 16:46:03.000000000 
+0200
@@ -46,9 +46,12 @@
                return "", err
        }
        if _, err = w.Write(b); err != nil {
+               w.Close()
+               return "", err
+       }
+       if err = w.Close(); err != nil {
                return "", err
        }
-       w.Close()
 
        return b64.EncodeToString(buf.Bytes()), nil
 }

++++++ helm.obsinfo ++++++
--- /var/tmp/diff_new_pack.vMvqPH/_old  2026-08-22 21:37:32.500218610 +0200
+++ /var/tmp/diff_new_pack.vMvqPH/_new  2026-08-22 21:37:32.505218789 +0200
@@ -1,5 +1,5 @@
 name: helm
-version: 4.2.3
-mtime: 1783628144
-commit: 43e8b7feece8beb0fcba47059ec9b522fd929a64
+version: 4.2.4
+mtime: 1786632363
+commit: 3900f434fd3ef2b84065dc04508df48f288dba00
 

Reply via email to