From 88bf9db3e04617eee0dea87b41a545aa3659b1d1 Mon Sep 17 00:00:00 2001 From: nicholasSUSE Date: Fri, 3 Oct 2025 19:17:08 -0300 Subject: [PATCH] fixed proper url for registries --- pkg/auto/oci.go | 89 +--------- pkg/auto/oci_test.go | 411 ++++++++++++++++++++++--------------------- 2 files changed, 219 insertions(+), 281 deletions(-) diff --git a/pkg/auto/oci.go b/pkg/auto/oci.go index c553ef6d..b1a7fed7 100644 --- a/pkg/auto/oci.go +++ b/pkg/auto/oci.go @@ -2,23 +2,16 @@ package auto import ( "context" - "crypto/tls" "errors" "fmt" "log/slog" - "net/http" "os" "strings" "github.com/go-git/go-billy/v5" - "github.com/google/go-containerregistry/pkg/authn" - "github.com/google/go-containerregistry/pkg/name" - "github.com/google/go-containerregistry/pkg/v1/remote" - "github.com/google/go-containerregistry/pkg/v1/remote/transport" "github.com/rancher/charts-build-scripts/pkg/logger" "github.com/rancher/charts-build-scripts/pkg/options" "github.com/rancher/charts-build-scripts/pkg/path" - "github.com/rancher/charts-build-scripts/pkg/registries" "helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/cli" @@ -30,14 +23,13 @@ type checkAssetFunc func(ctx context.Context, regClient *registry.Client, ociDNS type pushFunc func(helmClient *registry.Client, data []byte, url string) error type oci struct { - DNS string - user string - password string - helmClient *registry.Client - registryOptions []remote.Option - loadAsset loadAssetFunc - checkAsset checkAssetFunc - push pushFunc + DNS string + user string + password string + helmClient *registry.Client + loadAsset loadAssetFunc + checkAsset checkAssetFunc + push pushFunc } // UpdateOCI pushes Helm charts to an OCI registry @@ -78,8 +70,6 @@ func setupOCI(ctx context.Context, ociDNS, ociUser, ociPass string, debug bool) return nil, err } - o.registryOptions = setupRegistryReader(ctx, o.DNS, o.user, o.password) - o.loadAsset = loadAsset o.checkAsset = checkAsset o.push = push @@ -87,22 +77,6 @@ func setupOCI(ctx context.Context, ociDNS, ociUser, ociPass string, debug bool) return o, nil } -func setupRegistryReader(ctx context.Context, ociDNS, ociUser, ociPass string) []remote.Option { - tr := http.DefaultTransport.(*http.Transport).Clone() - tr.TLSClientConfig = &tls.Config{ - InsecureSkipVerify: false, - } - - registryClientOpts := []remote.Option{ - remote.WithContext(ctx), - remote.WithUserAgent(registries.UaString), - remote.WithAuth(&authn.Basic{Username: ociUser, Password: ociPass}), - remote.WithTransport(tr), - } - - return registryClientOpts -} - func setupHelm(ctx context.Context, ociDNS, ociUser, ociPass string, debug bool) (*registry.Client, error) { settings := cli.New() actionConfig := new(action.Configuration) @@ -206,13 +180,6 @@ func (o *oci) update(ctx context.Context, release *options.ReleaseOptions) ([]st // Check if the asset version already exists in the OCI registry // Never overwrite a previously released chart! - existsTest, err := o.checkRegistryTagExists(ctx, o.DNS, chart, version) - if err != nil { - logger.Log(ctx, slog.LevelError, "checkRegistryTagExists") - return pushedAssets, err - } - logger.Log(ctx, slog.LevelWarn, "exists worked?", slog.Bool("exist", existsTest)) - exists, err := o.checkAsset(ctx, o.helmClient, o.DNS, chart, version) if err != nil { return pushedAssets, err @@ -281,7 +248,7 @@ func loadAsset(chart, asset string) ([]byte, error) { // oci:///: func buildPushURL(ociDNS, chart, version string) string { - return ociDNS + "/" + chart + ":" + version + return ociDNS + "/rancher/charts/" + chart + ":" + version } // checkAsset checks if a specific asset version exists in the OCI registry @@ -289,10 +256,6 @@ func checkAsset(ctx context.Context, helmClient *registry.Client, ociDNS, chart, // Once issue is resolved: https://github.com/helm/helm/issues/13368 // Replace by: helmClient.Tags(ociDNS + "/" + chart + ":" + version) tagsURL := ociDNS + "/rancher/charts/" + chart - logger.Log(ctx, slog.LevelDebug, "checking tags", - slog.String("ociDNS", ociDNS), - slog.String("chart", chart), - slog.String("fullURL", tagsURL)) existingVersions, err := helmClient.Tags(tagsURL) if err != nil { if strings.Contains(err.Error(), "unexpected status code 404: name unknown: repository name not known to registry") { @@ -311,39 +274,3 @@ func checkAsset(ctx context.Context, helmClient *registry.Client, ociDNS, chart, return false, nil } - -// checkRegistryTagExists checks if a given source already exists at the target Registry -func (o *oci) checkRegistryTagExists(ctx context.Context, ociDNS, chart, tag string) (bool, error) { - var nameOpts []name.Option - nameOpts = append(nameOpts, name.StrictValidation) - nameOpts = append(nameOpts, name.Insecure) - - ociTag := strings.ReplaceAll(tag, "+", "_") - - // Build repository reference first (host + path, no tag) - repoStr := ociDNS + "/rancher/charts/" + chart - repo, err := name.NewRepository(repoStr, nameOpts...) - if err != nil { - logger.Log(ctx, slog.LevelError, "failed to parse repository", logger.Err(err)) - return false, err - } - // Then create tag reference from repository - dst := repo.Tag(ociTag) - - // ---------------------------------------------------- - exist := true - if _, err := remote.Head(dst, o.registryOptions...); err != nil { - exist = false - - var te *transport.Error - if errors.As(err, &te) && te.StatusCode == http.StatusNotFound { - // 404s are not treated as errors, means the img/tag does not exist - err = nil - } else { - logger.Log(ctx, slog.LevelError, "failure to check prime tag", logger.Err(err)) - } - } - - logger.Log(ctx, slog.LevelDebug, "checking", slog.Bool("exist", exist), slog.String("dst", dst.Name())) - return exist, err -} diff --git a/pkg/auto/oci_test.go b/pkg/auto/oci_test.go index ee9f5766..3737e376 100644 --- a/pkg/auto/oci_test.go +++ b/pkg/auto/oci_test.go @@ -1,206 +1,217 @@ package auto -// func Test_push(t *testing.T) { -// type input struct { -// o *oci -// release options.ReleaseOptions -// } -// type expected struct { -// pushedAssets []string -// err error -// } +import ( + "context" + "errors" + "strings" + "testing" -// tests := []struct { -// name string -// input input -// expected expected -// }{ -// { -// name: "Test #1", -// input: input{ -// o: &oci{ -// DNS: "######", -// user: "######", -// password: "######", -// helmClient: ®istry.Client{}, -// loadAsset: func(chart, asset string) ([]byte, error) { -// return []byte{}, nil -// }, -// checkAsset: func(ctx context.Context, regClient *registry.Client, ociDNS, chart, version string) (bool, error) { -// return false, nil -// }, -// push: func(helmClient *registry.Client, data []byte, url string) error { -// return nil -// }, -// }, -// release: options.ReleaseOptions{ -// "chart1": {"1.0.0"}, -// }, -// }, -// expected: expected{ -// pushedAssets: []string{"chart1-1.0.0.tgz"}, -// err: nil, -// }, -// }, -// { -// name: "Test #2", -// input: input{ -// o: &oci{ -// DNS: "######", -// user: "######", -// password: "######", -// helmClient: ®istry.Client{}, -// loadAsset: func(chart, asset string) ([]byte, error) { -// return []byte{}, nil -// }, -// checkAsset: func(ctx context.Context, regClient *registry.Client, ociDNS, chart, version string) (bool, error) { -// return false, nil -// }, -// push: func(helmClient *registry.Client, data []byte, url string) error { -// return nil -// }, -// }, -// release: options.ReleaseOptions{ -// "chart1": {"1.0.0+up0.0.0"}, -// "chart2": {"1.0.0+up0.0.0"}, -// "chart3": {"1.0.0+up0.0.0"}, -// }, -// }, -// expected: expected{ -// pushedAssets: []string{ -// "chart1-1.0.0+up0.0.0.tgz", -// "chart2-1.0.0+up0.0.0.tgz", -// "chart3-1.0.0+up0.0.0.tgz", -// }, -// err: nil, -// }, -// }, -// { -// name: "Test #3", -// input: input{ -// o: &oci{ -// DNS: "######", -// user: "######", -// password: "######", -// helmClient: ®istry.Client{}, -// loadAsset: func(chart, asset string) ([]byte, error) { -// return []byte{}, errors.New("some-error") -// }, -// checkAsset: func(ctx context.Context, regClient *registry.Client, ociDNS, chart, version string) (bool, error) { -// return false, nil -// }, -// push: func(helmClient *registry.Client, data []byte, url string) error { -// return nil -// }, -// }, -// release: options.ReleaseOptions{ -// "chart1": {"1.0.0+up0.0.0"}, -// }, -// }, -// expected: expected{ -// pushedAssets: []string{}, -// err: errors.New("some-error"), -// }, -// }, -// { -// name: "Test #4", -// input: input{ -// o: &oci{ -// DNS: "######", -// user: "######", -// password: "######", -// helmClient: ®istry.Client{}, -// loadAsset: func(chart, asset string) ([]byte, error) { -// return []byte{}, nil -// }, -// checkAsset: func(ctx context.Context, regClient *registry.Client, ociDNS, chart, version string) (bool, error) { -// return false, errors.New("some-error") -// }, -// push: func(helmClient *registry.Client, data []byte, url string) error { -// return nil -// }, -// }, -// release: options.ReleaseOptions{ -// "chart1": {"1.0.0+up0.0.0"}, -// }, -// }, -// expected: expected{ -// pushedAssets: []string{}, -// err: errors.New("some-error"), -// }, -// }, -// { -// name: "Test #5", -// input: input{ -// o: &oci{ -// DNS: "######", -// user: "######", -// password: "######", -// helmClient: ®istry.Client{}, -// loadAsset: func(chart, asset string) ([]byte, error) { -// return []byte{}, nil -// }, -// checkAsset: func(ctx context.Context, regClient *registry.Client, ociDNS, chart, version string) (bool, error) { -// return true, nil -// }, -// push: func(helmClient *registry.Client, data []byte, url string) error { -// return nil -// }, -// }, -// release: options.ReleaseOptions{ -// "chart1": {"1.0.0+up0.0.0"}, -// }, -// }, -// expected: expected{ -// pushedAssets: []string{}, -// err: nil, -// }, -// }, -// { -// name: "Test #6", -// input: input{ -// o: &oci{ -// DNS: "######", -// user: "######", -// password: "######", -// helmClient: ®istry.Client{}, -// loadAsset: func(chart, asset string) ([]byte, error) { -// return []byte{}, nil -// }, -// checkAsset: func(ctx context.Context, regClient *registry.Client, ociDNS, chart, version string) (bool, error) { -// return false, nil -// }, -// push: func(helmClient *registry.Client, data []byte, url string) error { -// err := errors.New("some assets failed, please fix and retry only these assets") -// return err -// }, -// }, -// release: options.ReleaseOptions{ -// "chart1": {"1.0.0+up0.0.0"}, -// }, -// }, -// expected: expected{ -// pushedAssets: []string{}, -// err: errors.New("some assets failed, please fix and retry only these assets"), -// }, -// }, -// } + "github.com/rancher/charts-build-scripts/pkg/options" + "github.com/stretchr/testify/assert" + "helm.sh/helm/v3/pkg/registry" +) -// for _, test := range tests { -// t.Run(test.name, func(t *testing.T) { -// assets, err := test.input.o.update(context.Background(), &test.input.release) -// if test.expected.err == nil { -// if err != nil { -// t.Errorf("Expected no error, got: [%v]", err) -// } -// } else { -// if !strings.Contains(err.Error(), test.expected.err.Error()) { -// t.Errorf("Expected error: [%v], got: [%v]", test.expected.err, err) -// } -// } +func Test_push(t *testing.T) { + type input struct { + o *oci + release options.ReleaseOptions + } + type expected struct { + pushedAssets []string + err error + } -// assert.EqualValues(t, len(assets), len(test.expected.pushedAssets)) -// }) -// } + tests := []struct { + name string + input input + expected expected + }{ + { + name: "Test #1", + input: input{ + o: &oci{ + DNS: "######", + user: "######", + password: "######", + helmClient: ®istry.Client{}, + loadAsset: func(chart, asset string) ([]byte, error) { + return []byte{}, nil + }, + checkAsset: func(ctx context.Context, regClient *registry.Client, ociDNS, chart, version string) (bool, error) { + return false, nil + }, + push: func(helmClient *registry.Client, data []byte, url string) error { + return nil + }, + }, + release: options.ReleaseOptions{ + "chart1": {"1.0.0"}, + }, + }, + expected: expected{ + pushedAssets: []string{"chart1-1.0.0.tgz"}, + err: nil, + }, + }, + { + name: "Test #2", + input: input{ + o: &oci{ + DNS: "######", + user: "######", + password: "######", + helmClient: ®istry.Client{}, + loadAsset: func(chart, asset string) ([]byte, error) { + return []byte{}, nil + }, + checkAsset: func(ctx context.Context, regClient *registry.Client, ociDNS, chart, version string) (bool, error) { + return false, nil + }, + push: func(helmClient *registry.Client, data []byte, url string) error { + return nil + }, + }, + release: options.ReleaseOptions{ + "chart1": {"1.0.0+up0.0.0"}, + "chart2": {"1.0.0+up0.0.0"}, + "chart3": {"1.0.0+up0.0.0"}, + }, + }, + expected: expected{ + pushedAssets: []string{ + "chart1-1.0.0+up0.0.0.tgz", + "chart2-1.0.0+up0.0.0.tgz", + "chart3-1.0.0+up0.0.0.tgz", + }, + err: nil, + }, + }, + { + name: "Test #3", + input: input{ + o: &oci{ + DNS: "######", + user: "######", + password: "######", + helmClient: ®istry.Client{}, + loadAsset: func(chart, asset string) ([]byte, error) { + return []byte{}, errors.New("some-error") + }, + checkAsset: func(ctx context.Context, regClient *registry.Client, ociDNS, chart, version string) (bool, error) { + return false, nil + }, + push: func(helmClient *registry.Client, data []byte, url string) error { + return nil + }, + }, + release: options.ReleaseOptions{ + "chart1": {"1.0.0+up0.0.0"}, + }, + }, + expected: expected{ + pushedAssets: []string{}, + err: errors.New("some-error"), + }, + }, + { + name: "Test #4", + input: input{ + o: &oci{ + DNS: "######", + user: "######", + password: "######", + helmClient: ®istry.Client{}, + loadAsset: func(chart, asset string) ([]byte, error) { + return []byte{}, nil + }, + checkAsset: func(ctx context.Context, regClient *registry.Client, ociDNS, chart, version string) (bool, error) { + return false, errors.New("some-error") + }, + push: func(helmClient *registry.Client, data []byte, url string) error { + return nil + }, + }, + release: options.ReleaseOptions{ + "chart1": {"1.0.0+up0.0.0"}, + }, + }, + expected: expected{ + pushedAssets: []string{}, + err: errors.New("some-error"), + }, + }, + { + name: "Test #5", + input: input{ + o: &oci{ + DNS: "######", + user: "######", + password: "######", + helmClient: ®istry.Client{}, + loadAsset: func(chart, asset string) ([]byte, error) { + return []byte{}, nil + }, + checkAsset: func(ctx context.Context, regClient *registry.Client, ociDNS, chart, version string) (bool, error) { + return true, nil + }, + push: func(helmClient *registry.Client, data []byte, url string) error { + return nil + }, + }, + release: options.ReleaseOptions{ + "chart1": {"1.0.0+up0.0.0"}, + }, + }, + expected: expected{ + pushedAssets: []string{}, + err: nil, + }, + }, + { + name: "Test #6", + input: input{ + o: &oci{ + DNS: "######", + user: "######", + password: "######", + helmClient: ®istry.Client{}, + loadAsset: func(chart, asset string) ([]byte, error) { + return []byte{}, nil + }, + checkAsset: func(ctx context.Context, regClient *registry.Client, ociDNS, chart, version string) (bool, error) { + return false, nil + }, + push: func(helmClient *registry.Client, data []byte, url string) error { + err := errors.New("some assets failed, please fix and retry only these assets") + return err + }, + }, + release: options.ReleaseOptions{ + "chart1": {"1.0.0+up0.0.0"}, + }, + }, + expected: expected{ + pushedAssets: []string{}, + err: errors.New("some assets failed, please fix and retry only these assets"), + }, + }, + } -// } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + assets, err := test.input.o.update(context.Background(), &test.input.release) + if test.expected.err == nil { + if err != nil { + t.Errorf("Expected no error, got: [%v]", err) + } + } else { + if !strings.Contains(err.Error(), test.expected.err.Error()) { + t.Errorf("Expected error: [%v], got: [%v]", test.expected.err, err) + } + } + + assert.EqualValues(t, len(assets), len(test.expected.pushedAssets)) + }) + } + +}