mirror of https://github.com/helm/helm
Merge c9270177f0 into 543b94d673
commit
73fa4d9fd9
@ -0,0 +1,56 @@
|
||||
/*
|
||||
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 cmd
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// chartSource resolves the location a chart was installed or upgraded from, for
|
||||
// persistence under action.ReleaseSourceAnnotation. A repository URL (when
|
||||
// supplied) is preferred over the local chart reference, and any embedded
|
||||
// credentials are stripped before the value is returned. The result is handed
|
||||
// to the install/upgrade action, which records it on the release after
|
||||
// rendering so it is never exposed to templates via .Chart.Annotations.
|
||||
func chartSource(chartRef, repoURL string) string {
|
||||
source := chartRef
|
||||
if repoURL != "" {
|
||||
source = repoURL
|
||||
}
|
||||
return sanitizeChartSource(source)
|
||||
}
|
||||
|
||||
// sanitizeChartSource strips any user credentials and other potentially
|
||||
// sensitive components (query string, fragment) from a chart source URL before
|
||||
// it is persisted into the release record, so secrets embedded in a repo URL
|
||||
// (e.g. https://user:pass@host) are not leaked into cluster metadata. Sources
|
||||
// that are not URLs (local paths or chart references) are returned unchanged.
|
||||
//
|
||||
// Only sources with a host component (i.e. scheme://host/...) are treated as
|
||||
// URLs. This deliberately excludes local filesystem paths, including Windows
|
||||
// absolute paths such as C:\charts\mychart, which url.Parse would otherwise
|
||||
// interpret as a "c" scheme and re-encode (e.g. c:%5Ccharts%5Cmychart).
|
||||
func sanitizeChartSource(source string) string {
|
||||
u, err := url.Parse(source)
|
||||
if err != nil || u.Scheme == "" || u.Host == "" {
|
||||
return source
|
||||
}
|
||||
u.User = nil
|
||||
u.RawQuery = ""
|
||||
u.Fragment = ""
|
||||
return u.String()
|
||||
}
|
||||
@ -0,0 +1,101 @@
|
||||
/*
|
||||
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 cmd
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestSanitizeChartSource(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
source string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "strips userinfo from https URL",
|
||||
source: "https://user:pass@charts.example.com/mychart",
|
||||
want: "https://charts.example.com/mychart",
|
||||
},
|
||||
{
|
||||
name: "strips username-only userinfo",
|
||||
source: "https://user@charts.example.com/mychart",
|
||||
want: "https://charts.example.com/mychart",
|
||||
},
|
||||
{
|
||||
name: "strips query string and fragment",
|
||||
source: "https://charts.example.com/index.yaml?token=secret#section",
|
||||
want: "https://charts.example.com/index.yaml",
|
||||
},
|
||||
{
|
||||
name: "strips userinfo, query and fragment together",
|
||||
source: "https://user:pass@charts.example.com/index.yaml?token=secret#frag",
|
||||
want: "https://charts.example.com/index.yaml",
|
||||
},
|
||||
{
|
||||
name: "strips userinfo from oci URL",
|
||||
source: "oci://user:pass@registry.example.com/charts/mychart",
|
||||
want: "oci://registry.example.com/charts/mychart",
|
||||
},
|
||||
{
|
||||
name: "leaves credential-free https URL unchanged",
|
||||
source: "https://charts.example.com/mychart",
|
||||
want: "https://charts.example.com/mychart",
|
||||
},
|
||||
{
|
||||
name: "leaves chart reference unchanged",
|
||||
source: "stable/mychart",
|
||||
want: "stable/mychart",
|
||||
},
|
||||
{
|
||||
name: "leaves relative local path unchanged",
|
||||
source: "./charts/mychart",
|
||||
want: "./charts/mychart",
|
||||
},
|
||||
{
|
||||
name: "leaves absolute unix path unchanged",
|
||||
source: "/var/charts/mychart",
|
||||
want: "/var/charts/mychart",
|
||||
},
|
||||
{
|
||||
name: "leaves windows absolute path unchanged",
|
||||
source: `C:\charts\mychart`,
|
||||
want: `C:\charts\mychart`,
|
||||
},
|
||||
{
|
||||
name: "leaves windows forward-slash path unchanged",
|
||||
source: "C:/charts/mychart",
|
||||
want: "C:/charts/mychart",
|
||||
},
|
||||
{
|
||||
name: "leaves bare chart name unchanged",
|
||||
source: "mychart",
|
||||
want: "mychart",
|
||||
},
|
||||
{
|
||||
name: "leaves empty source unchanged",
|
||||
source: "",
|
||||
want: "",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := sanitizeChartSource(tt.source); got != tt.want {
|
||||
t.Errorf("sanitizeChartSource(%q) = %q, want %q", tt.source, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
{"name":"thomas-guide","chart":"foo","version":"0.1.0-beta.1","appVersion":"1.0","source":"https://charts.example.com","annotations":{"category":"web-apps","meta.helm.sh/release-source":"https://charts.example.com","supported":"true"},"labels":{"key1":"value1"},"dependencies":[{"name":"cool-plugin","version":"1.0.0","repository":"https://coolplugin.io/charts","condition":"coolPlugin.enabled","enabled":true},{"name":"crds","version":"2.7.1","repository":"","condition":"crds.enabled"}],"namespace":"default","revision":1,"status":"deployed","deployedAt":"1977-09-02T22:04:05Z"}
|
||||
@ -0,0 +1,13 @@
|
||||
NAME: thomas-guide
|
||||
CHART: foo
|
||||
VERSION: 0.1.0-beta.1
|
||||
APP_VERSION: 1.0
|
||||
SOURCE: https://charts.example.com
|
||||
ANNOTATIONS: category=web-apps,meta.helm.sh/release-source=https://charts.example.com,supported=true
|
||||
LABELS: key1=value1
|
||||
DEPENDENCIES: cool-plugin,crds
|
||||
NAMESPACE: default
|
||||
REVISION: 1
|
||||
STATUS: deployed
|
||||
DEPLOYED_AT: 1977-09-02T22:04:05Z
|
||||
APPLY_METHOD: client-side apply (defaulted)
|
||||
@ -0,0 +1,25 @@
|
||||
annotations:
|
||||
category: web-apps
|
||||
meta.helm.sh/release-source: https://charts.example.com
|
||||
supported: "true"
|
||||
appVersion: "1.0"
|
||||
chart: foo
|
||||
dependencies:
|
||||
- condition: coolPlugin.enabled
|
||||
enabled: true
|
||||
name: cool-plugin
|
||||
repository: https://coolplugin.io/charts
|
||||
version: 1.0.0
|
||||
- condition: crds.enabled
|
||||
name: crds
|
||||
repository: ""
|
||||
version: 2.7.1
|
||||
deployedAt: "1977-09-02T22:04:05Z"
|
||||
labels:
|
||||
key1: value1
|
||||
name: thomas-guide
|
||||
namespace: default
|
||||
revision: 1
|
||||
source: https://charts.example.com
|
||||
status: deployed
|
||||
version: 0.1.0-beta.1
|
||||
@ -1 +1 @@
|
||||
[{"name":"test-release","namespace":"default","revision":"1","updated":"2016-01-16 00:00:00 +0000 UTC","status":"deployed","chart":"test-chart-1.0.0","app_version":"0.0.1"}]
|
||||
[{"name":"test-release","namespace":"default","revision":"1","updated":"2016-01-16 00:00:00 +0000 UTC","status":"deployed","chart":"test-chart-1.0.0","app_version":"0.0.1","source":"https://example.com/repo"}]
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION SOURCE
|
||||
drax default 1 2016-01-16 00:00:01 +0000 UTC uninstalling chickadee-1.0.0 0.0.1 https://example.com/repo
|
||||
gamora default 1 2016-01-16 00:00:01 +0000 UTC superseded chickadee-1.0.0 0.0.1 https://example.com/repo
|
||||
groot default 1 2016-01-16 00:00:01 +0000 UTC uninstalled chickadee-1.0.0 0.0.1 https://example.com/repo
|
||||
hummingbird default 1 2016-01-16 00:00:03 +0000 UTC deployed chickadee-1.0.0 0.0.1 https://example.com/repo
|
||||
iguana default 2 2016-01-16 00:00:04 +0000 UTC deployed chickadee-1.0.0 0.0.1 https://example.com/repo
|
||||
rocket default 1 2016-01-16 00:00:02 +0000 UTC failed chickadee-1.0.0 0.0.1 https://example.com/repo
|
||||
starlord default 2 2016-01-16 00:00:01 +0000 UTC deployed chickadee-1.0.0 0.0.1 https://example.com/repo
|
||||
thanos default 1 2016-01-16 00:00:01 +0000 UTC pending-install chickadee-1.0.0 0.0.1 https://example.com/repo
|
||||
Loading…
Reference in new issue