fix: decouple provenance from --repo input; reset downloader state

- ChartDownloader.repositoryURL is now cleared at the start of
    ResolveChartVersion and set in the absolute-URL branch too, so
    reused downloaders don't report stale URLs.
  - New ChartPathOptions.ResolvedRepoURL() carries provenance from
    LocateChart so it no longer overwrites the --repo input field.
    Install/Upgrade actions stamp metadata.RepoURL from it first,
    falling back to RepoURL for consumers that bypass LocateChart.
  - Align RepoURL doc strings in chart v2 and v3 metadata.

Signed-off-by: Aleksei Krugliak <aleksei.krugliak@altenar.com>
pull/31792/head
Aleksei Krugliak 4 months ago
parent 97e54c8f11
commit 99a52b1d46

@ -81,7 +81,8 @@ type Metadata struct {
Dependencies []*Dependency `json:"dependencies,omitempty"`
// Specifies the chart type: application or library
Type string `json:"type,omitempty"`
// Specifies the chart URL that was used to initially install a chart.
// The URL from which the chart was obtained (a Helm repository URL,
// an OCI reference, or a direct artifact URL). Used to record provenance.
RepoURL string `json:"repoURL,omitempty"`
}

@ -153,6 +153,19 @@ type ChartPathOptions struct {
// registryClient provides a registry client but is not added with
// options from a flag
registryClient *registry.Client
// resolvedRepoURL is the source URL from which the chart was obtained
// during the last LocateChart call. It is independent of RepoURL
// (the --repo input) and is used to record provenance into chart metadata.
resolvedRepoURL string
}
// ResolvedRepoURL returns the source URL from which the chart was obtained
// during the last LocateChart call (a Helm repository URL, an OCI reference,
// or a direct artifact URL). It is empty for local-path installs or when
// LocateChart has not been called.
func (c *ChartPathOptions) ResolvedRepoURL() string {
return c.resolvedRepoURL
}
// NewInstall creates a new Install object with the given configuration.
@ -352,12 +365,14 @@ func (i *Install) RunWithContext(ctx context.Context, ch ci.Charter, vals map[st
return nil, fmt.Errorf("user supplied labels contains system reserved label name. System labels: %+v", driver.GetSystemLabels())
}
// Stamp provenance information into the chart metadata if available from
// the ChartPathOptions. Do not overwrite existing metadata.RepoURL set by
// the chart itself. This ensures library consumers who call actions get
// provenance filled in when LocateChart or a downloader discovered it.
// Stamp provenance information into the chart metadata. Prefer the URL
// discovered by LocateChart (ResolvedRepoURL) and fall back to the --repo
// input for library consumers who set it without calling LocateChart.
// Do not overwrite a value already set in Chart.yaml.
if chrt.Metadata != nil && chrt.Metadata.RepoURL == "" {
if i.ChartPathOptions.RepoURL != "" {
if u := i.ChartPathOptions.ResolvedRepoURL(); u != "" {
chrt.Metadata.RepoURL = u
} else if i.ChartPathOptions.RepoURL != "" {
chrt.Metadata.RepoURL = i.ChartPathOptions.RepoURL
}
}
@ -896,6 +911,10 @@ func (c *ChartPathOptions) LocateChart(name string, settings *cli.EnvSettings) (
return "", fmt.Errorf("unable to lookup chart %q, missing registry client", name)
}
// Reset any provenance recorded by a previous call so callers that reuse
// this instance do not observe stale values from an earlier chart.
c.resolvedRepoURL = ""
name = strings.TrimSpace(name)
version := strings.TrimSpace(c.Version)
@ -990,13 +1009,19 @@ func (c *ChartPathOptions) LocateChart(name string, settings *cli.EnvSettings) (
}
// Record provenance information about where the chart was resolved from.
// Prefer the URL discovered by the downloader; fall back to the original
// reference when it is an OCI ref or an absolute URL. Leave RepoURL empty
// for local paths and unresolvable references so callers can distinguish.
if u := dl.RepositoryURL(); u != "" {
c.RepoURL = u
} else if c.RepoURL == "" && isRemoteChartRef(name) {
c.RepoURL = name
// Prefer the URL discovered by the downloader, then the --repo input,
// then the original reference when it is an OCI ref or an absolute URL.
// Local paths and unresolvable references leave resolvedRepoURL empty so
// callers can distinguish them. We deliberately do not mutate RepoURL,
// because it is also the --repo flag input and controls local-path vs
// remote resolution on subsequent calls.
switch {
case dl.RepositoryURL() != "":
c.resolvedRepoURL = dl.RepositoryURL()
case c.RepoURL != "":
c.resolvedRepoURL = c.RepoURL
case isRemoteChartRef(name):
c.resolvedRepoURL = name
}
lname, err := filepath.Abs(filename)

@ -312,11 +312,14 @@ func (u *Upgrade) prepareUpgrade(name string, chart *chartv2.Chart, vals map[str
u.cfg.Logger().Debug("determined release apply method", slog.Bool("server_side_apply", serverSideApply), slog.String("previous_release_apply_method", lastRelease.ApplyMethod))
// Stamp provenance information into the chart metadata if available from
// the ChartPathOptions. Only set it when chart metadata doesn't already
// contain a RepoURL so we don't overwrite embedded provenance.
// Stamp provenance information into the chart metadata. Prefer the URL
// discovered by LocateChart (ResolvedRepoURL) and fall back to the --repo
// input for library consumers who set it without calling LocateChart.
// Do not overwrite a value already set in Chart.yaml.
if chart.Metadata != nil && chart.Metadata.RepoURL == "" {
if u.ChartPathOptions.RepoURL != "" {
if r := u.ChartPathOptions.ResolvedRepoURL(); r != "" {
chart.Metadata.RepoURL = r
} else if u.ChartPathOptions.RepoURL != "" {
chart.Metadata.RepoURL = u.ChartPathOptions.RepoURL
}
}

@ -52,7 +52,8 @@ type Metadata struct {
Home string `json:"home,omitempty"`
// Source is the URL to the source code of this chart
Sources []string `json:"sources,omitempty"`
// The URL to the chart's repository (provenance information)
// The URL from which the chart was obtained (a Helm repository URL,
// an OCI reference, or a direct artifact URL). Used to record provenance.
RepoURL string `json:"repoURL,omitempty"`
// A version string of the chart. Required.
Version string `json:"version,omitempty"`

@ -359,6 +359,11 @@ func (c *ChartDownloader) DownloadToCache(ref, version string) (string, *provena
//
// TODO: support OCI hash
func (c *ChartDownloader) ResolveChartVersion(ref, version string) (string, *url.URL, error) {
// Clear any URL recorded by a previous call so RepositoryURL() does not
// report stale provenance when the same ChartDownloader instance is
// reused for a chart that does not resolve to a configured repo.
c.repositoryURL = ""
u, err := url.Parse(ref)
if err != nil {
return "", nil, fmt.Errorf("invalid chart URL format: %s", ref)
@ -399,6 +404,9 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (string, *url
// If we get here, we don't need to go through the next phase of looking
// up the URL. We have it already. So we just set the parameters and return.
if rc.URL != "" {
c.repositoryURL = rc.URL
}
c.Options = append(
c.Options,
getter.WithURL(rc.URL),

Loading…
Cancel
Save