diff --git a/internal/hub/external.go b/internal/hub/external.go index 23e4f5a8..d5a9fe2b 100644 --- a/internal/hub/external.go +++ b/internal/hub/external.go @@ -63,5 +63,10 @@ type OCISignatureChecker interface { // OCITagsGetter is the interface that wraps the Tags method, used to get all // the tags available for a given repository in a OCI registry. type OCITagsGetter interface { - Tags(ctx context.Context, r *Repository, onlySemver bool) ([]string, error) + Tags( + ctx context.Context, + r *Repository, + onlySemver bool, + restorePlusSign bool, + ) ([]string, error) } diff --git a/internal/oci/mock.go b/internal/oci/mock.go index f1e57cea..b7d5cb25 100644 --- a/internal/oci/mock.go +++ b/internal/oci/mock.go @@ -50,7 +50,12 @@ type TagsGetterMock struct { } // Tags implements the OCITagsGetter interface. -func (m *TagsGetterMock) Tags(ctx context.Context, r *hub.Repository, onlySemver bool) ([]string, error) { +func (m *TagsGetterMock) Tags( + ctx context.Context, + r *hub.Repository, + onlySemver bool, + restorePlusSign bool, +) ([]string, error) { args := m.Called(ctx, r, onlySemver) tags, _ := args.Get(0).([]string) return tags, args.Error(1) diff --git a/internal/oci/oci.go b/internal/oci/oci.go index 16dbce26..6bcab285 100644 --- a/internal/oci/oci.go +++ b/internal/oci/oci.go @@ -168,7 +168,12 @@ func NewTagsGetter(cfg *viper.Viper) *TagsGetter { } // Tags returns a list with the tags available for the provided repository. -func (tg *TagsGetter) Tags(ctx context.Context, r *hub.Repository, onlySemver bool) ([]string, error) { +func (tg *TagsGetter) Tags( + ctx context.Context, + r *hub.Repository, + onlySemver bool, + restorePlusSign bool, +) ([]string, error) { ref, err := name.ParseReference(strings.TrimPrefix(r.URL, hub.RepositoryOCIPrefix)) if err != nil { return nil, err @@ -181,6 +186,10 @@ func (tg *TagsGetter) Tags(ctx context.Context, r *hub.Repository, onlySemver bo if onlySemver { var semverTags []string for _, tag := range tags { + if restorePlusSign { + // See https://github.com/helm/helm/blob/14d0c13e9eefff5b4a1b511cf50643529692ec94/pkg/registry/client.go#L45C8-L50 + tag = strings.Replace(tag, "_", "+", 1) + } if _, err := semver.NewVersion(tag); err == nil { semverTags = append(semverTags, tag) } diff --git a/internal/repo/manager.go b/internal/repo/manager.go index ceea1872..9b3cfa55 100644 --- a/internal/repo/manager.go +++ b/internal/repo/manager.go @@ -567,7 +567,7 @@ func (m *Manager) GetRemoteDigest(ctx context.Context, r *hub.Repository) (strin } case SchemeIsOCI(u): // Digest is obtained by hashing the list of versions available - versions, err := m.tg.Tags(ctx, r, true) + versions, err := m.tg.Tags(ctx, r, true, true) if err != nil { return digest, err } diff --git a/internal/tracker/source/helm/helm.go b/internal/tracker/source/helm/helm.go index 9eafafbe..c1ce80ec 100644 --- a/internal/tracker/source/helm/helm.go +++ b/internal/tracker/source/helm/helm.go @@ -189,7 +189,7 @@ func (s *TrackerSource) getCharts() (map[string][]*helmrepo.ChartVersion, error) } case "oci": // Get versions (tags) available in the repository - versions, err := s.tg.Tags(s.i.Svc.Ctx, s.i.Repository, true) + versions, err := s.tg.Tags(s.i.Svc.Ctx, s.i.Repository, true, true) if err != nil { return nil, fmt.Errorf("error getting repository available versions: %w", err) } @@ -197,12 +197,16 @@ func (s *TrackerSource) getCharts() (map[string][]*helmrepo.ChartVersion, error) // Prepare chart versions using the list of versions available name := path.Base(s.i.Repository.URL) for _, version := range versions { + // See https://github.com/helm/helm/blob/14d0c13e9eefff5b4a1b511cf50643529692ec94/pkg/registry/client.go#L45C8-L50 + versionReplacingPlusSign := strings.Replace(version, "+", "_", 1) + chartURL := fmt.Sprintf("%s:%s", s.i.Repository.URL, versionReplacingPlusSign) + charts[name] = append(charts[name], &helmrepo.ChartVersion{ Metadata: &chart.Metadata{ Name: name, Version: version, }, - URLs: []string{s.i.Repository.URL + ":" + version}, + URLs: []string{chartURL}, }) } default: