Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pkg/helm/actions/get_chart.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func GetChartFromURL(url string, conf *action.Configuration, namespace string, c
if err != nil {
return nil, err
}
if err := applyBasicAuthFromUserCredentials(cmd, userCredentials); err != nil {
if err := applyBasicAuthFromUserCredentials(&cmd.ChartPathOptions, cmd, userCredentials); err != nil {
return nil, err
}
}
Expand Down
24 changes: 21 additions & 3 deletions pkg/helm/actions/install_chart.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/chart/loader"
"helm.sh/helm/v3/pkg/registry"
"helm.sh/helm/v3/pkg/release"
kv1 "k8s.io/api/core/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand Down Expand Up @@ -48,6 +49,14 @@ var (
httpURLRe = regexp.MustCompile(`(?i)^https?://` + hostPort + `/.+\.(?:tar\.gz|tgz)$`)
)

const (
helmAuthSecretAnnotation = "helm.openshift.io/auth-secret"
)

type RegistryClientSetter interface {
SetRegistryClient(rc *registry.Client)
}

// isValidChartURL validates chart URLs using RFC-compliant hostname labels.
// Accepts oci://<registry>/<path> and http(s)://<host>/<path>.tgz|tar.gz URLs.
func isValidChartURL(raw string) bool {
Expand Down Expand Up @@ -281,17 +290,25 @@ func GetUserCredentials(coreClient corev1client.CoreV1Interface, ns, secretName
}

// applyBasicAuthFromSecret sets cmd.Username and cmd.Password from a userCredentials and sets the registry client
func applyBasicAuthFromUserCredentials(cmd *action.Install, userCredentials *UserCredentials) error {
func applyBasicAuthFromUserCredentials(cmd *action.ChartPathOptions, setter RegistryClientSetter, userCredentials *UserCredentials) error {
cmd.Username = userCredentials.Username
cmd.Password = userCredentials.Password
rc, err := GetOCIRegistry(false, false, userCredentials)
if err != nil {
return fmt.Errorf("failed to configure OCI registry client: %w", err)
}
cmd.SetRegistryClient(rc)
setter.SetRegistryClient(rc)
return nil
}

// addAuthSecretAnnotation adds the auth secret reference to the release annotations via chart metadata.
func addAuthSecretAnnotation(ch *chart.Chart, secretName string) {
if secretName == "" {
return
}
ch.Metadata.Annotations[helmAuthSecretAnnotation] = secretName
}

// InstallChartFromURL installs a chart from an OCI or direct HTTP(S) chart URL.
// If not provided, version is extracted from the OCI URL tag when applicable.
// basicAuthSecretName names a Secret in ns containing username and password keys for registry auth.
Expand All @@ -312,7 +329,7 @@ func InstallChartFromURL(ns, name, url string, vals map[string]interface{}, conf
if err != nil {
return nil, err
}
if err := applyBasicAuthFromUserCredentials(cmd, userCredentials); err != nil {
if err := applyBasicAuthFromUserCredentials(&cmd.ChartPathOptions, cmd, userCredentials); err != nil {
return nil, err
}
}
Expand Down Expand Up @@ -345,6 +362,7 @@ func InstallChartFromURL(ns, name, url string, vals map[string]interface{}, conf
}
ch.Metadata.Annotations["chart_url"] = url
ch.Metadata.Annotations["installation"] = "url_install"
addAuthSecretAnnotation(ch, basicAuthSecretName)
go func() {
_, err := cmd.Run(ch, vals)
if err == nil {
Expand Down
19 changes: 19 additions & 0 deletions pkg/helm/actions/upgrade_release.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/dynamic"
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/klog/v2"
)

func UpgradeRelease(
Expand Down Expand Up @@ -158,11 +159,15 @@ func UpgradeReleaseAsync(
return nil, err
}

auth_secret := ""
// Before proceeding, check if chart URL is present as an annotation
if rel.Chart.Metadata.Annotations != nil {
if chart_url, ok := rel.Chart.Metadata.Annotations["chart_url"]; chartUrl == "" && ok {
chartUrl = chart_url
}
if authSecret, ok := rel.Chart.Metadata.Annotations[helmAuthSecretAnnotation]; ok {
auth_secret = authSecret
}
}

var tlsFiles []*os.File
Expand Down Expand Up @@ -224,6 +229,20 @@ func UpgradeReleaseAsync(
}
ch.Metadata.Annotations["chart_url"] = chartUrl
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should helmAuthSecretAnnotation also be written here alongside chart_url? My thinking is that on a second upgrade, the annotation would already be gone from the stored release, so the secret lookup would fail. Could be wrong though, curious what you think. I have not tested out the changes myself.

}
if auth_secret != "" {
klog.Infof("Found persisted auth secret %s for release %s/%s, applying credentials for upgrade", auth_secret, releaseNamespace, releaseName)
userCredentials, err := GetUserCredentials(coreClient, releaseNamespace, auth_secret)
if err != nil {
klog.Infof("Failed to get user credentials for release upgrade %s/%s: %v", releaseNamespace, releaseName, err)

} else {
if err := applyBasicAuthFromUserCredentials(&client.ChartPathOptions, client, userCredentials); err != nil {
klog.Errorf("Failed to apply auth from secret %s for release %s/%s: %v", auth_secret, releaseNamespace, releaseName, err)
// Continue with upgrade but log the error - the upgrade may still work if auth is not required
}
}

}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
go func() {
_, err := client.Run(releaseName, ch, vals)
if err != nil {
Expand Down