diff --git a/cmd/asset-syncer/server/utils.go b/cmd/asset-syncer/server/utils.go index 8dac2206ee2..91e0cae0bfb 100644 --- a/cmd/asset-syncer/server/utils.go +++ b/cmd/asset-syncer/server/utils.go @@ -197,6 +197,13 @@ func unescapeChartsData(charts []models.Chart) []models.Chart { // Unescape string or return value itself if error func unescapeOrDefaultValue(value string) string { + // Ensure any escaped `/` (%2F) in a chart name will remain escaped. + // Kubeapps splits the chart ID, such as "repo-name/harbor-project%2Fchart-name", on the slash. + // See PR comment at + // https://github.com/vmware-tanzu/kubeapps/pull/3863#pullrequestreview-819141298 + // and instance of the issue cropping up via Harbor at + // https://github.com/vmware-tanzu/kubeapps/issues/5897 + value = strings.Replace(value, "%2F", "%252F", -1) unescapedValue, err := url.PathUnescape(value) if err != nil { return value diff --git a/cmd/asset-syncer/server/utils_test.go b/cmd/asset-syncer/server/utils_test.go index 99b5bffd34c..d258943793f 100644 --- a/cmd/asset-syncer/server/utils_test.go +++ b/cmd/asset-syncer/server/utils_test.go @@ -1376,6 +1376,21 @@ func TestUnescapeChartsData(t *testing.T) { {Name: "foo#bar.bar"}, }, }, + { + "slashes in the chart name are not unescaped", + []models.Chart{ + { + ID: "repo-name/project1%2Ffoo%20bar", + Name: "project1%2Ffoo%20bar", + }, + }, + []models.Chart{ + { + ID: "repo-name/project1%2Ffoo bar", + Name: "project1%2Ffoo bar", + }, + }, + }, } for _, tt := range tests { t.Run(tt.description, func(t *testing.T) { diff --git a/pkg/helm/index.go b/pkg/helm/index.go index e8b46cc0882..d446faa64d7 100644 --- a/pkg/helm/index.go +++ b/pkg/helm/index.go @@ -48,11 +48,9 @@ func newChart(entry repo.ChartVersions, r *models.Repo, shallow bool) models.Cha return c } -// // ChartsFromIndex receives an array of bytes containing the contents of index.yaml from a helm repo and returns // all Chart models from that index. The shallow flag controls whether only the latest version of the charts is returned // or all versions -// func ChartsFromIndex(contents []byte, r *models.Repo, shallow bool) ([]models.Chart, error) { var charts []models.Chart index, err := parseRepoIndex(contents) diff --git a/pkg/helm/index_test.go b/pkg/helm/index_test.go index 1ca221e3487..0e45880cbe8 100644 --- a/pkg/helm/index_test.go +++ b/pkg/helm/index_test.go @@ -14,6 +14,9 @@ import ( var validRepoIndexYAMLBytes, _ = os.ReadFile("testdata/valid-index.yaml") var validRepoIndexYAML = string(validRepoIndexYAMLBytes) +var validRepoIndexHarborUnifiedYAMLBytes, _ = os.ReadFile("testdata/valid-index-harbor-unified.yaml") +var validRepoIndexHarborUnifiedYAML = string(validRepoIndexHarborUnifiedYAMLBytes) + func Test_parseRepoIndex(t *testing.T) { tests := []struct { name string @@ -52,6 +55,16 @@ func Test_chartsFromIndex(t *testing.T) { assert.Equal(t, len(charts[1].ChartVersions), 2, "number of versions") } +func Test_chartsFromIndexHarborUnified(t *testing.T) { + r := &models.Repo{Name: "test", URL: "http://testrepo.com"} + charts, err := ChartsFromIndex([]byte(validRepoIndexHarborUnifiedYAML), r, false) + assert.NoError(t, err) + assert.Equal(t, len(charts), 2, "number of charts") + + assert.Equal(t, charts[0].Name, "project1%2Facs-engine-autoscaler") + assert.Equal(t, charts[1].Name, "project2%2Fwordpress") +} + func Test_shallowChartsFromIndex(t *testing.T) { r := &models.Repo{Name: "test", URL: "http://testrepo.com"} charts, err := ChartsFromIndex([]byte(validRepoIndexYAML), r, true) diff --git a/pkg/helm/testdata/valid-index-harbor-unified.yaml b/pkg/helm/testdata/valid-index-harbor-unified.yaml new file mode 100644 index 00000000000..3f2691f6e56 --- /dev/null +++ b/pkg/helm/testdata/valid-index-harbor-unified.yaml @@ -0,0 +1,73 @@ +# Copyright 2021-2022 the Kubeapps contributors. +# SPDX-License-Identifier: Apache-2.0 + +--- +entries: + project1/acs-engine-autoscaler: + - apiVersion: v1 + appVersion: 2.1.1 + created: 2017-12-06T18:48:59.568323124Z + description: Scales worker nodes within agent pools + digest: 39e66eb53c310529bd9dd19776f8ba662e063a4ebd51fc5ec9f2267e2e073e3e + icon: https://github.com/kubernetes/kubernetes/blob/master/logo/logo.png + maintainers: + - email: ritazh@microsoft.com + name: ritazh + - email: wibuch@microsoft.com + name: wbuchwalter + name: project1/acs-engine-autoscaler + sources: + - https://github.com/wbuchwalter/Kubernetes-acs-engine-autoscaler + urls: + - https://kubernetes-charts.storage.googleapis.com/acs-engine-autoscaler-2.1.1.tgz + version: 2.1.1 + project2/wordpress: + - appVersion: 4.9.1 + created: 2017-12-06T18:48:59.644981487Z + description: new description! + digest: 74889e60a35dcffa4686f88bb23de863fed2b6e63a69b1f4858dde37c301885c + engine: gotpl + home: http://www.wordpress.com/ + icon: https://bitnami.com/assets/stacks/wordpress/img/wordpress-stack-220x234.png + keywords: + - wordpress + - cms + - blog + - http + - web + - application + - php + maintainers: + - email: containers@bitnami.com + name: bitnami-bot + name: project2/wordpress + sources: + - https://github.com/bitnami/bitnami-docker-wordpress + urls: + - https://kubernetes-charts.storage.googleapis.com/wordpress-0.7.5.tgz + version: 0.7.5 + - appVersion: 4.9.0 + created: 2017-12-01T11:49:00.136950565Z + description: Web publishing platform for building blogs and websites. + digest: a69139ef3008eeb11ca60261ec2ded61e84ce7db32bb3626056e84bcff7ec270 + engine: gotpl + home: http://www.wordpress.com/ + icon: https://bitnami.com/assets/stacks/wordpress/img/wordpress-stack-220x234.png + keywords: + - wordpress + - cms + - cms + - blog + - http + - web + - application + - php + maintainers: + - email: containers@bitnami.com + name: bitnami-bot + name: wordpress + sources: + - https://github.com/bitnami/bitnami-docker-wordpress + urls: + - https://kubernetes-charts.storage.googleapis.com/wordpress-0.7.4.tgz + version: 0.7.4