mirror of https://github.com/helm/helm
Record where a release's chart was installed or upgraded from and surface it via `helm list` and `helm get metadata` — addressing both surfaces called out in #4256. `helm install` and `helm upgrade` set a `meta.helm.sh/release-source` annotation on the chart metadata (the `--repo` URL when supplied, otherwise the chart reference). The annotation is written after any `--dependency-update` chart reload so it survives the reload, and any credentials embedded in a repo URL are stripped before the value is persisted so secrets are not leaked into the release record. - `helm list`: new `source` field in JSON/YAML output (omitted when empty, so existing releases keep their schema) plus an opt-in `--show-source` flag for the table column, leaving the default table layout unchanged for scripts that parse it. - `helm get metadata`: new `source` field, shown in the table only when set. Closes #4256 Signed-off-by: Shaan Satsangi <shaansatsangi@gmail.com>pull/32250/head
parent
74fa4fceb8
commit
fc2a5e3fec
@ -0,0 +1,77 @@
|
||||
/*
|
||||
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"
|
||||
|
||||
v3chart "helm.sh/helm/v4/internal/chart/v3"
|
||||
"helm.sh/helm/v4/pkg/action"
|
||||
"helm.sh/helm/v4/pkg/chart"
|
||||
v2chart "helm.sh/helm/v4/pkg/chart/v2"
|
||||
)
|
||||
|
||||
// setReleaseSource records, on the chart's metadata, the location the chart was
|
||||
// installed or upgraded from so it can be surfaced by 'helm list --show-source'.
|
||||
// A repository URL (when supplied) is preferred over the local chart reference,
|
||||
// and any embedded credentials are stripped before the value is persisted.
|
||||
//
|
||||
// It accepts the loader's chart.Charter (which may be either a v2 or v3 chart)
|
||||
// and is a no-op for any unrecognized chart type, so callers never need to
|
||||
// reason about the concrete chart version.
|
||||
func setReleaseSource(chrt chart.Charter, chartRef, repoURL string) {
|
||||
source := chartRef
|
||||
if repoURL != "" {
|
||||
source = repoURL
|
||||
}
|
||||
source = sanitizeChartSource(source)
|
||||
|
||||
switch c := chrt.(type) {
|
||||
case *v2chart.Chart:
|
||||
if c.Metadata == nil {
|
||||
c.Metadata = &v2chart.Metadata{}
|
||||
}
|
||||
if c.Metadata.Annotations == nil {
|
||||
c.Metadata.Annotations = make(map[string]string)
|
||||
}
|
||||
c.Metadata.Annotations[action.ReleaseSourceAnnotation] = source
|
||||
case *v3chart.Chart:
|
||||
if c.Metadata == nil {
|
||||
c.Metadata = &v3chart.Metadata{}
|
||||
}
|
||||
if c.Metadata.Annotations == nil {
|
||||
c.Metadata.Annotations = make(map[string]string)
|
||||
}
|
||||
c.Metadata.Annotations[action.ReleaseSourceAnnotation] = 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.
|
||||
func sanitizeChartSource(source string) string {
|
||||
u, err := url.Parse(source)
|
||||
if err != nil || u.Scheme == "" {
|
||||
return source
|
||||
}
|
||||
u.User = nil
|
||||
u.RawQuery = ""
|
||||
u.Fragment = ""
|
||||
return u.String()
|
||||
}
|
||||
@ -0,0 +1,86 @@
|
||||
/*
|
||||
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 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -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