Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package helm for openSUSE:Factory checked in at 2025-06-11 16:22:14 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/helm (Old) and /work/SRC/openSUSE:Factory/.helm.new.19631 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "helm" Wed Jun 11 16:22:14 2025 rev:83 rq:1284412 version:3.18.2 Changes: -------- --- /work/SRC/openSUSE:Factory/helm/helm.changes 2025-05-26 18:36:18.481371332 +0200 +++ /work/SRC/openSUSE:Factory/.helm.new.19631/helm.changes 2025-06-11 16:23:24.564670285 +0200 @@ -1,0 +2,45 @@ +Tue Jun 10 08:14:00 UTC 2025 - Johannes Kastl <opensuse_buildserv...@ojkastl.de> + +- remove flaky test + * cmd/helm/pull_test.go + * cmd/helm/registry_login_test.go + * cmd/helm/dependency_update_test.go + +------------------------------------------------------------------- +Mon Jun 02 15:44:48 UTC 2025 - Johannes Kastl <opensuse_buildserv...@ojkastl.de> + +- Update to version 3.18.2: + * fix: legacy docker support broken for login 04cad46 (Terry + Howe) + * Handle an empty registry config file. bc9f8a2 (Matt Farina) + +------------------------------------------------------------------- +Sat May 31 05:20:36 UTC 2025 - Johannes Kastl <opensuse_buildserv...@ojkastl.de> + +- Update to version 3.18.1: + * Notes: + - This release fixes regressions around template generation and + OCI registry interaction in 3.18.0 + - There are at least 2 known regressions unaddressed in this + release. They are being worked on. + - Empty registry configuration files. When the file exists + but it is empty. + - Login to Docker Hub on some domains fails. + * Changelog + - fix(client): skipnode utilization for PreCopy + - fix(client): layers now returns manifest - remove duplicate + from descriptors + - fix(client): return nil on non-allowed media types + - Prevent fetching newReference again as we have in calling + method + - Prevent failure when resolving version tags in oras memory + store + - Update pkg/plugin/plugin.go + - Update pkg/plugin/plugin.go + - Wait for Helm v4 before raising when platformCommand and + Command are set + - Fix 3.18.0 regression: registry login with scheme + - Revert "fix (helm) : toToml` renders int as float [ backport + to v3 ]" + +------------------------------------------------------------------- Old: ---- helm-3.18.0.obscpio New: ---- helm-3.18.2.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ helm.spec ++++++ --- /var/tmp/diff_new_pack.hUkQSw/_old 2025-06-11 16:23:25.352703170 +0200 +++ /var/tmp/diff_new_pack.hUkQSw/_new 2025-06-11 16:23:25.352703170 +0200 @@ -19,7 +19,7 @@ %define goipath helm.sh/helm/v3 %define git_dirty clean Name: helm -Version: 3.18.0 +Version: 3.18.2 Release: 0 Summary: The Kubernetes Package Manager License: Apache-2.0 @@ -103,6 +103,11 @@ # requires network rm -v pkg/plugin/installer/*installer_test.go rm -v pkg/engine/engine_test.go +# skip flaky tests +rm -v cmd/helm/dependency_build_test.go +rm -v cmd/helm/dependency_update_test.go +rm -v cmd/helm/pull_test.go +rm -v cmd/helm/registry_login_test.go GO111MODULE=on go test -p 2 ./... %files ++++++ _service ++++++ --- /var/tmp/diff_new_pack.hUkQSw/_old 2025-06-11 16:23:25.384704505 +0200 +++ /var/tmp/diff_new_pack.hUkQSw/_new 2025-06-11 16:23:25.384704505 +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">v3.18.0</param> + <param name="revision">v3.18.2</param> <param name="changesgenerate">enable</param> </service> <service name="set_version" mode="manual"> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.hUkQSw/_old 2025-06-11 16:23:25.404705340 +0200 +++ /var/tmp/diff_new_pack.hUkQSw/_new 2025-06-11 16:23:25.416705841 +0200 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/helm/helm.git</param> - <param name="changesrevision">cc58e3f5a3aa615c6a86275e6f4444b5fdd3cc4e</param></service></servicedata> + <param name="changesrevision">04cad4610054e5d546aa5c5d9c1b1d5cf68ec1f8</param></service></servicedata> (No newline at EOF) ++++++ helm-3.18.0.obscpio -> helm-3.18.2.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/helm-3.18.0/cmd/helm/registry_login_test.go new/helm-3.18.2/cmd/helm/registry_login_test.go --- old/helm-3.18.0/cmd/helm/registry_login_test.go 2025-05-15 00:00:36.000000000 +0200 +++ new/helm-3.18.2/cmd/helm/registry_login_test.go 2025-05-31 18:13:47.000000000 +0200 @@ -17,9 +17,73 @@ package main import ( + "fmt" + "os" + "path/filepath" "testing" + + "helm.sh/helm/v3/pkg/repo/repotest" ) func TestRegistryLoginFileCompletion(t *testing.T) { checkFileCompletion(t, "registry login", false) } + +func TestRegistryLogin(t *testing.T) { + srv, err := repotest.NewTempServerWithCleanup(t, "testdata/testcharts/*.tgz*") + if err != nil { + t.Fatal(err) + } + defer srv.Stop() + + ociSrv, err := repotest.NewOCIServer(t, srv.Root()) + if err != nil { + t.Fatal(err) + } + ociSrv.Run(t) + + // Creating an empty json file to use as an empty registry configuration file. Used for + // testing the handling of this situation. + tmpDir := t.TempDir() + emptyFile, err := os.Create(filepath.Join(tmpDir, "empty.json")) + if err != nil { + t.Fatal(err) + } + emptyFile.Close() + + tests := []struct { + name string + cmd string + wantError bool + wantErrorMsg string + }{ + { + name: "Normal login", + cmd: fmt.Sprintf("registry login %s --username %s --password %s", ociSrv.RegistryURL, ociSrv.TestUsername, ociSrv.TestPassword), + }, + { + name: "Failed login", + cmd: fmt.Sprintf("registry login %s --username foo --password bar", ociSrv.RegistryURL), + wantError: true, + }, + { + name: "Normal login with empty registry file", + cmd: fmt.Sprintf("registry login %s --username %s --password %s --registry-config %s", ociSrv.RegistryURL, ociSrv.TestUsername, ociSrv.TestPassword, emptyFile.Name()), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, _, err := executeActionCommand(tt.cmd) + if err != nil { + if tt.wantError { + if tt.wantErrorMsg != "" && tt.wantErrorMsg == err.Error() { + t.Fatalf("Actual error %s, not equal to expected error %s", err, tt.wantErrorMsg) + } + return + } + t.Fatalf("%q reported error: %s", tt.name, err) + } + }) + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/helm-3.18.0/cmd/helm/template_test.go new/helm-3.18.2/cmd/helm/template_test.go --- old/helm-3.18.0/cmd/helm/template_test.go 2025-05-15 00:00:36.000000000 +0200 +++ new/helm-3.18.2/cmd/helm/template_test.go 2025-05-31 18:13:47.000000000 +0200 @@ -161,11 +161,6 @@ cmd: fmt.Sprintf("template '%s' -f %s/extra_values.yaml", chartPath, chartPath), golden: "output/template-subchart-cm-set-file.txt", }, - { - name: "check toToml function rendering", - cmd: fmt.Sprintf("template '%s'", "testdata/testcharts/issue-totoml"), - golden: "output/issue-totoml.txt", - }, } runTestCmd(t, tests) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/helm-3.18.0/cmd/helm/testdata/output/issue-totoml.txt new/helm-3.18.2/cmd/helm/testdata/output/issue-totoml.txt --- old/helm-3.18.0/cmd/helm/testdata/output/issue-totoml.txt 2025-05-15 00:00:36.000000000 +0200 +++ new/helm-3.18.2/cmd/helm/testdata/output/issue-totoml.txt 1970-01-01 01:00:00.000000000 +0100 @@ -1,8 +0,0 @@ ---- -# Source: issue-totoml/templates/configmap.yaml -apiVersion: v1 -kind: ConfigMap -metadata: - name: issue-totoml -data: | - key = 13 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/helm-3.18.0/cmd/helm/testdata/testcharts/issue-totoml/Chart.yaml new/helm-3.18.2/cmd/helm/testdata/testcharts/issue-totoml/Chart.yaml --- old/helm-3.18.0/cmd/helm/testdata/testcharts/issue-totoml/Chart.yaml 2025-05-15 00:00:36.000000000 +0200 +++ new/helm-3.18.2/cmd/helm/testdata/testcharts/issue-totoml/Chart.yaml 1970-01-01 01:00:00.000000000 +0100 @@ -1,3 +0,0 @@ -apiVersion: v2 -name: issue-totoml -version: 0.1.0 \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/helm-3.18.0/cmd/helm/testdata/testcharts/issue-totoml/templates/configmap.yaml new/helm-3.18.2/cmd/helm/testdata/testcharts/issue-totoml/templates/configmap.yaml --- old/helm-3.18.0/cmd/helm/testdata/testcharts/issue-totoml/templates/configmap.yaml 2025-05-15 00:00:36.000000000 +0200 +++ new/helm-3.18.2/cmd/helm/testdata/testcharts/issue-totoml/templates/configmap.yaml 1970-01-01 01:00:00.000000000 +0100 @@ -1,6 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: issue-totoml -data: | - {{ .Values.global | toToml }} \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/helm-3.18.0/cmd/helm/testdata/testcharts/issue-totoml/values.yaml new/helm-3.18.2/cmd/helm/testdata/testcharts/issue-totoml/values.yaml --- old/helm-3.18.0/cmd/helm/testdata/testcharts/issue-totoml/values.yaml 2025-05-15 00:00:36.000000000 +0200 +++ new/helm-3.18.2/cmd/helm/testdata/testcharts/issue-totoml/values.yaml 1970-01-01 01:00:00.000000000 +0100 @@ -1,2 +0,0 @@ -global: - key: 13 \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/helm-3.18.0/pkg/chart/loader/load.go new/helm-3.18.2/pkg/chart/loader/load.go --- old/helm-3.18.0/pkg/chart/loader/load.go 2025-05-15 00:00:36.000000000 +0200 +++ new/helm-3.18.2/pkg/chart/loader/load.go 2025-05-31 18:13:47.000000000 +0200 @@ -18,7 +18,6 @@ import ( "bytes" - "encoding/json" "log" "os" "path/filepath" @@ -105,10 +104,7 @@ } case f.Name == "values.yaml": c.Values = make(map[string]interface{}) - if err := yaml.Unmarshal(f.Data, &c.Values, func(d *json.Decoder) *json.Decoder { - d.UseNumber() - return d - }); err != nil { + if err := yaml.Unmarshal(f.Data, &c.Values); err != nil { return c, errors.Wrap(err, "cannot load values.yaml") } case f.Name == "values.schema.json": diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/helm-3.18.0/pkg/chartutil/dependencies_test.go new/helm-3.18.2/pkg/chartutil/dependencies_test.go --- old/helm-3.18.0/pkg/chartutil/dependencies_test.go 2025-05-15 00:00:36.000000000 +0200 +++ new/helm-3.18.2/pkg/chartutil/dependencies_test.go 2025-05-31 18:13:47.000000000 +0200 @@ -15,7 +15,6 @@ package chartutil import ( - "encoding/json" "os" "path/filepath" "sort" @@ -238,20 +237,6 @@ if b := strconv.FormatBool(pv); b != vv { t.Errorf("failed to match imported bool value %v with expected %v for key %q", b, vv, kk) } - case json.Number: - if fv, err := pv.Float64(); err == nil { - if sfv := strconv.FormatFloat(fv, 'f', -1, 64); sfv != vv { - t.Errorf("failed to match imported float value %v with expected %v for key %q", sfv, vv, kk) - } - } - if iv, err := pv.Int64(); err == nil { - if siv := strconv.FormatInt(iv, 10); siv != vv { - t.Errorf("failed to match imported int value %v with expected %v for key %q", siv, vv, kk) - } - } - if pv.String() != vv { - t.Errorf("failed to match imported string value %q with expected %q for key %q", pv, vv, kk) - } default: if pv != vv { t.Errorf("failed to match imported string value %q with expected %q for key %q", pv, vv, kk) @@ -324,10 +309,6 @@ if s := strconv.FormatFloat(pv, 'f', -1, 64); s != vv { t.Errorf("failed to match imported float value %v with expected %v", s, vv) } - case json.Number: - if pv.String() != vv { - t.Errorf("failed to match imported string value %q with expected %q", pv, vv) - } default: if pv != vv { t.Errorf("failed to match imported string value %q with expected %q", pv, vv) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/helm-3.18.0/pkg/chartutil/values.go new/helm-3.18.2/pkg/chartutil/values.go --- old/helm-3.18.0/pkg/chartutil/values.go 2025-05-15 00:00:36.000000000 +0200 +++ new/helm-3.18.2/pkg/chartutil/values.go 2025-05-31 18:13:47.000000000 +0200 @@ -17,7 +17,6 @@ package chartutil import ( - "encoding/json" "fmt" "io" "os" @@ -106,10 +105,7 @@ // ReadValues will parse YAML byte data into a Values. func ReadValues(data []byte) (vals Values, err error) { - err = yaml.Unmarshal(data, &vals, func(d *json.Decoder) *json.Decoder { - d.UseNumber() - return d - }) + err = yaml.Unmarshal(data, &vals) if len(vals) == 0 { vals = Values{} } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/helm-3.18.0/pkg/plugin/plugin.go new/helm-3.18.2/pkg/plugin/plugin.go --- old/helm-3.18.0/pkg/plugin/plugin.go 2025-05-15 00:00:36.000000000 +0200 +++ new/helm-3.18.2/pkg/plugin/plugin.go 2025-05-31 18:13:47.000000000 +0200 @@ -84,7 +84,7 @@ PlatformCommand []PlatformCommand `json:"platformCommand"` // Command is the plugin command, as a single string. - // Providing a command will result in an error if PlatformCommand is also set. + // Providing a command will result in an deprecation warning if PlatformCommand is also set. // // The command will be passed through environment expansion, so env vars can // be present in this command. Unless IgnoreFlags is set, this will @@ -266,11 +266,11 @@ plug.Metadata.Usage = sanitizeString(plug.Metadata.Usage) if len(plug.Metadata.PlatformCommand) > 0 && len(plug.Metadata.Command) > 0 { - return fmt.Errorf("both platformCommand and command are set in %q", filepath) + fmt.Printf("WARNING: both 'platformCommand' and 'command' are set in %q (this will become an error in a future Helm version)\n", filepath) } if len(plug.Metadata.PlatformHooks) > 0 && len(plug.Metadata.Hooks) > 0 { - return fmt.Errorf("both platformHooks and hooks are set in %q", filepath) + fmt.Printf("WARNING: both 'platformHooks' and 'hooks' are set in %q (this will become an error in a future Helm version)\n", filepath) } // We could also validate SemVer, executable, and other fields should we so choose. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/helm-3.18.0/pkg/plugin/plugin_test.go new/helm-3.18.2/pkg/plugin/plugin_test.go --- old/helm-3.18.0/pkg/plugin/plugin_test.go 2025-05-15 00:00:36.000000000 +0200 +++ new/helm-3.18.2/pkg/plugin/plugin_test.go 2025-05-31 18:13:47.000000000 +0200 @@ -496,8 +496,8 @@ {false, mockMissingMeta}, // Test if the metadata section missing {true, mockNoCommand}, // Test no command metadata works {true, mockLegacyCommand}, // Test legacy command metadata works - {false, mockWithCommand}, // Test platformCommand and command both set fails - {false, mockWithHooks}, // Test platformHooks and hooks both set fails + {true, mockWithCommand}, // Test platformCommand and command both set pass until v4 + {true, mockWithHooks}, // Test platformHooks and hooks both set pass until v4 } { err := validatePluginData(item.plug, fmt.Sprintf("test-%d", i)) if item.pass && err != nil { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/helm-3.18.0/pkg/registry/client.go new/helm-3.18.2/pkg/registry/client.go --- old/helm-3.18.0/pkg/registry/client.go 2025-05-15 00:00:36.000000000 +0200 +++ new/helm-3.18.2/pkg/registry/client.go 2025-05-31 18:13:47.000000000 +0200 @@ -81,6 +81,9 @@ httpClient *http.Client plainHTTP bool err error // pass any errors from the ClientOption functions + + // credentialsFileTemp captures if the empty file / EOF work around is being used. + credentialsFileTemp bool } // ClientOption allows specifying various settings configurable by the user for overriding the defaults @@ -115,11 +118,26 @@ } store, err := credentials.NewStore(client.credentialsFile, storeOptions) if err != nil { - return nil, err + // If the file exists and is empty there will be an EOF error. This error is not wrapped so + // a check with errors.Is will not work. The only way to capture it is an EOF error is + // with string parsing. + // This handling passes no file location which will cause NewStore to invoke its + // fault tolerance for a file not existing. A bool records this bypass so that if the + // credential store needs to be written to it this work around can be handled. See the + // Login method for more details. + if strings.Contains(err.Error(), "invalid config format: EOF") { + var err2 error + store, err2 = credentials.NewStore("", storeOptions) + if err2 != nil { + return nil, err + } + client.credentialsFileTemp = true + } else { + return nil, err + } } dockerStore, err := credentials.NewStoreFromDocker(storeOptions) if err != nil { - // should only fail if user home directory can't be determined client.credentialsStore = store } else { // use Helm credentials with fallback to Docker @@ -229,8 +247,39 @@ } ) +// Deprecated: will be removed in Helm 4 +// Added for backwards compatibility for Helm < 3.18.0 after moving to ORAS v2 +// ref: https://github.com/helm/helm/issues/30873 +// TODO: document that Helm 4 `registry login` does accept full URLs +func (c *Client) stripURL(host string) string { + // strip scheme from host in URL + for _, s := range []string{"oci://", "http://", "https://"} { + if strings.HasPrefix(host, s) { + plain := strings.TrimPrefix(host, s) + if c.debug { + fmt.Fprintf(c.out, "[WARNING] Invalid registry passed: registries should NOT be prefixed with a URL scheme. Use %q instead\n", plain) + } + host = plain + break + } + } + // strip repo from registry in URL + if idx := strings.Index(host, "/"); idx != -1 { + host = host[:idx] + if c.debug { + fmt.Fprintf(c.out, "[WARNING] Invalid registry passed: registries should NOT include a repository. Use %q instead\n", host) + } + return host + } + + return host +} + // Login logs into a registry func (c *Client) Login(host string, options ...LoginOption) error { + // This is the lowest available point to strip incorrect URL parts + host = c.stripURL(host) + for _, option := range options { option(&loginOperation{host, c}) } @@ -252,7 +301,32 @@ return fmt.Errorf("authenticating to %q: %w", host, err) } + // The credentialsStore loader does not handle empty files. So, there is a workaround. + // This can be removed when the credentials loader can handle empty files. + // When Helm catches an empty file error it causes the loader to trigger its fault + // tolerance for a file not existing and records it with a bool. If that bool is set and the + // file needs to be written, the file needs to be put into a usable state and loaded + // properly. + // See the NewClient function for the bypass setup. + if c.credentialsFileTemp { + err = os.WriteFile(c.credentialsFile, []byte("{}"), 0600) + if err != nil { + return err + } + storeOptions := credentials.StoreOptions{ + AllowPlaintextPut: true, + DetectDefaultNativeStore: true, + } + store, err := credentials.NewStore(c.credentialsFile, storeOptions) + if err != nil { + return err + } + c.credentialsStore = store + c.credentialsFileTemp = false + } + key := credentials.ServerAddressFromRegistry(host) + key = credentials.ServerAddressFromHostname(key) if err := c.credentialsStore.Put(ctx, key, cred); err != nil { return err } @@ -459,7 +533,7 @@ PreCopy: func(_ context.Context, desc ocispec.Descriptor) error { mediaType := desc.MediaType if i := sort.SearchStrings(allowedMediaTypes, mediaType); i >= len(allowedMediaTypes) || allowedMediaTypes[i] != mediaType { - return errors.Errorf("media type %q is not allowed, found in descriptor with digest: %q", mediaType, desc.Digest) + return oras.SkipNode } mu.Lock() @@ -473,7 +547,6 @@ return nil, err } - descriptors = append(descriptors, manifest) descriptors = append(descriptors, layers...) numDescriptors := len(descriptors) @@ -681,19 +754,9 @@ }) ociAnnotations := generateOCIAnnotations(meta, operation.creationTime) - manifest := ocispec.Manifest{ - Versioned: specs.Versioned{SchemaVersion: 2}, - Config: configDescriptor, - Layers: layers, - Annotations: ociAnnotations, - } - - manifestData, err := json.Marshal(manifest) - if err != nil { - return nil, err - } - manifestDescriptor, err := oras.TagBytes(ctx, memoryStore, ocispec.MediaTypeImageManifest, manifestData, ref) + manifestDescriptor, err := c.tagManifest(ctx, memoryStore, configDescriptor, + layers, ociAnnotations, parsedRef) if err != nil { return nil, err } @@ -894,3 +957,24 @@ return u, err } + +// tagManifest prepares and tags a manifest in memory storage +func (c *Client) tagManifest(ctx context.Context, memoryStore *memory.Store, + configDescriptor ocispec.Descriptor, layers []ocispec.Descriptor, + ociAnnotations map[string]string, parsedRef reference) (ocispec.Descriptor, error) { + + manifest := ocispec.Manifest{ + Versioned: specs.Versioned{SchemaVersion: 2}, + Config: configDescriptor, + Layers: layers, + Annotations: ociAnnotations, + } + + manifestData, err := json.Marshal(manifest) + if err != nil { + return ocispec.Descriptor{}, err + } + + return oras.TagBytes(ctx, memoryStore, ocispec.MediaTypeImageManifest, + manifestData, parsedRef.String()) +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/helm-3.18.0/pkg/registry/client_test.go new/helm-3.18.2/pkg/registry/client_test.go --- old/helm-3.18.0/pkg/registry/client_test.go 2025-05-15 00:00:36.000000000 +0200 +++ new/helm-3.18.2/pkg/registry/client_test.go 2025-05-31 18:13:47.000000000 +0200 @@ -17,11 +17,15 @@ package registry import ( + "context" + "io" "testing" "github.com/containerd/containerd/remotes" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "oras.land/oras-go/v2/content/memory" ) func TestNewClientResolverNotSupported(t *testing.T) { @@ -31,3 +35,50 @@ require.Equal(t, err, errDeprecatedRemote) assert.Nil(t, client) } + +func TestStripURL(t *testing.T) { + client := &Client{ + out: io.Discard, + } + // no change with supported host formats + assert.Equal(t, "username@localhost:8000", client.stripURL("username@localhost:8000")) + assert.Equal(t, "localhost:8000", client.stripURL("localhost:8000")) + assert.Equal(t, "docker.pkg.dev", client.stripURL("docker.pkg.dev")) + + // test strip scheme from host in URL + assert.Equal(t, "docker.pkg.dev", client.stripURL("oci://docker.pkg.dev")) + assert.Equal(t, "docker.pkg.dev", client.stripURL("http://docker.pkg.dev")) + assert.Equal(t, "docker.pkg.dev", client.stripURL("https://docker.pkg.dev")) + + // test strip repo from Registry in URL + assert.Equal(t, "127.0.0.1:15000", client.stripURL("127.0.0.1:15000/asdf")) + assert.Equal(t, "127.0.0.1:15000", client.stripURL("127.0.0.1:15000/asdf/asdf")) + assert.Equal(t, "127.0.0.1:15000", client.stripURL("127.0.0.1:15000")) +} + +// Inspired by oras test +// https://github.com/oras-project/oras-go/blob/05a2b09cbf2eab1df691411884dc4df741ec56ab/content_test.go#L1802 +func TestTagManifestTransformsReferences(t *testing.T) { + memStore := memory.New() + client := &Client{out: io.Discard} + ctx := context.Background() + + refWithPlus := "test-registry.io/charts/test:1.0.0+metadata" + expectedRef := "test-registry.io/charts/test:1.0.0_metadata" // + becomes _ + + configDesc := ocispec.Descriptor{MediaType: ConfigMediaType, Digest: "sha256:config", Size: 100} + layers := []ocispec.Descriptor{{MediaType: ChartLayerMediaType, Digest: "sha256:layer", Size: 200}} + + parsedRef, err := newReference(refWithPlus) + require.NoError(t, err) + + desc, err := client.tagManifest(ctx, memStore, configDesc, layers, nil, parsedRef) + require.NoError(t, err) + + transformedDesc, err := memStore.Resolve(ctx, expectedRef) + require.NoError(t, err, "Should find the reference with _ instead of +") + require.Equal(t, desc.Digest, transformedDesc.Digest) + + _, err = memStore.Resolve(ctx, refWithPlus) + require.Error(t, err, "Should NOT find the reference with the original +") +} ++++++ helm.obsinfo ++++++ --- /var/tmp/diff_new_pack.hUkQSw/_old 2025-06-11 16:23:25.940727708 +0200 +++ /var/tmp/diff_new_pack.hUkQSw/_new 2025-06-11 16:23:25.944727875 +0200 @@ -1,5 +1,5 @@ name: helm -version: 3.18.0 -mtime: 1747260036 -commit: cc58e3f5a3aa615c6a86275e6f4444b5fdd3cc4e +version: 3.18.2 +mtime: 1748708027 +commit: 04cad4610054e5d546aa5c5d9c1b1d5cf68ec1f8 ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/helm/vendor.tar.gz /work/SRC/openSUSE:Factory/.helm.new.19631/vendor.tar.gz differ: char 13, line 1