mirror of
https://github.com/hanzoai/deploy.git
synced 2026-10-07 08:44:50 +00:00
feat: Migrate from Helm 3 to Helm 4 (#28076)
Signed-off-by: reggie-k <[email protected]>
This commit is contained in:
@@ -208,7 +208,9 @@ func NewRepoAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
errors.Fatal(errors.ErrorGeneric, "Must specify --name for repos of type 'helm'")
|
||||
}
|
||||
|
||||
if repoOpts.Repo.Type == "oci" && repoOpts.InsecureOCIForceHTTP {
|
||||
if repoOpts.InsecureOCIForceHTTP {
|
||||
err := cmdutil.ValidateInsecureOCIForceHTTP(repoOpts.InsecureOCIForceHTTP, repoOpts.Repo.Type, repoOpts.Repo.EnableOCI)
|
||||
errors.CheckError(err)
|
||||
repoOpts.Repo.InsecureOCIForceHttp = repoOpts.InsecureOCIForceHTTP
|
||||
}
|
||||
|
||||
|
||||
@@ -180,6 +180,9 @@ func NewRepoCredsAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comma
|
||||
err = cmdutil.ValidateBearerTokenForHTTPSRepoOnly(repo.BearerToken, git.IsHTTPSURL(repo.URL))
|
||||
errors.CheckError(err)
|
||||
|
||||
err = cmdutil.ValidateInsecureOCIForceHTTP(repo.InsecureOCIForceHttp, repo.Type, repo.EnableOCI)
|
||||
errors.CheckError(err)
|
||||
|
||||
repoCreateReq := repocredspkg.RepoCredsCreateRequest{
|
||||
Creds: &repo,
|
||||
Upsert: upsert,
|
||||
@@ -202,6 +205,7 @@ func NewRepoCredsAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comma
|
||||
command.Flags().StringVar(&repo.GitHubAppEnterpriseBaseURL, "github-app-enterprise-base-url", "", "base url to use when using GitHub Enterprise (e.g. https://ghe.example.com/api/v3")
|
||||
command.Flags().BoolVar(&upsert, "upsert", false, "Override an existing repository with the same name even if the spec differs")
|
||||
command.Flags().BoolVar(&repo.EnableOCI, "enable-oci", false, "Specifies whether helm-oci support should be enabled for this repo")
|
||||
command.Flags().BoolVar(&repo.InsecureOCIForceHttp, "insecure-oci-force-http", false, "Use http when accessing an OCI repository")
|
||||
command.Flags().StringVar(&repo.Type, "type", common.DefaultRepoType, "type of the repository, \"git\" or \"helm\"")
|
||||
command.Flags().StringVar(&gcpServiceAccountKeyPath, "gcp-service-account-key-path", "", "service account key for the Google Cloud Platform")
|
||||
command.Flags().BoolVar(&repo.ForceHttpBasicAuth, "force-http-basic-auth", false, "whether to force basic auth when connecting via HTTP")
|
||||
|
||||
@@ -37,3 +37,13 @@ func ValidateBearerTokenAndPasswordCombo(bearerToken string, password string) er
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateInsecureOCIForceHTTP returns an error if --insecure-oci-force-http is set
|
||||
// on a repo that is not OCI-capable. Only type=oci repos, or type=helm repos with
|
||||
// --enable-oci, are OCI-capable; --enable-oci is meaningful only for helm repos.
|
||||
func ValidateInsecureOCIForceHTTP(insecureOCIForceHTTP bool, repoType string, enableOCI bool) error {
|
||||
if insecureOCIForceHTTP && repoType != "oci" && (repoType != "helm" || !enableOCI) {
|
||||
return stderrors.New("--insecure-oci-force-http requires --type oci or --enable-oci")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -153,3 +153,73 @@ func TestValidateBearerTokenForHTTPSRepoOnly(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateInsecureOCIForceHTTP(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
insecureOCIForceHTTP bool
|
||||
repoType string
|
||||
enableOCI bool
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
name: "type=oci with insecure-oci-force-http",
|
||||
insecureOCIForceHTTP: true,
|
||||
repoType: "oci",
|
||||
enableOCI: false,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "type=helm with enable-oci and insecure-oci-force-http",
|
||||
insecureOCIForceHTTP: true,
|
||||
repoType: "helm",
|
||||
enableOCI: true,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "type=helm without enable-oci and insecure-oci-force-http",
|
||||
insecureOCIForceHTTP: true,
|
||||
repoType: "helm",
|
||||
enableOCI: false,
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "type=git with insecure-oci-force-http",
|
||||
insecureOCIForceHTTP: true,
|
||||
repoType: "git",
|
||||
enableOCI: false,
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "type=git with enable-oci and insecure-oci-force-http",
|
||||
insecureOCIForceHTTP: true,
|
||||
repoType: "git",
|
||||
enableOCI: true,
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "insecure-oci-force-http not set on git repo",
|
||||
insecureOCIForceHTTP: false,
|
||||
repoType: "git",
|
||||
enableOCI: false,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "insecure-oci-force-http not set on helm repo",
|
||||
insecureOCIForceHTTP: false,
|
||||
repoType: "helm",
|
||||
enableOCI: false,
|
||||
expectError: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := ValidateInsecureOCIForceHTTP(tt.insecureOCIForceHTTP, tt.repoType, tt.enableOCI)
|
||||
if tt.expectError {
|
||||
require.ErrorContains(t, err, "--insecure-oci-force-http requires --type oci or --enable-oci")
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,47 @@
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
### Helm was upgraded to `4.2.0`.
|
||||
|
||||
In Helm v4, the OCI implementation is more strict: if the registry doesn't speak TLS, it is required to explicitly use `--plain-http` upon `helm push`, `helm registry login` and upon `helm dependency build`.
|
||||
|
||||
This is a breaking change for Argo CD users with plain HTTP OCI registries. Two actions may be required:
|
||||
|
||||
#### Set --insecure-oci-force-http on existing OCI repos
|
||||
|
||||
For any existing OCI repository that uses plain HTTP (not HTTPS), add the flag via CLI (CLI version 3.5): `repo add ... --insecure-oci-force-http --upsert`
|
||||
Or set it directly in the Kubernetes secret:
|
||||
```yaml
|
||||
stringData:
|
||||
insecureOCIForceHttp: "true"
|
||||
```
|
||||
|
||||
#### Explicitly register plain HTTP dependency repos
|
||||
|
||||
If your Helm charts have OCI dependencies (Chart.yaml dependencies with repository: `oci://...`) hosted on plain HTTP registries, those dependency repos must now be explicitly added to Argo CD with the `--insecure-oci-force-http` flag, the same way as described above. With Helm v3 this was not required — plain HTTP OCI dependency registries were accessed transparently without registration. With Helm v4, Argo CD needs to know which dependency registries use plain HTTP in order to pass `--plain-http` to `helm dependency build`.
|
||||
|
||||
#### Known limitation — conflicting TLS flags (Helm v4)
|
||||
|
||||
For Argo CD OCI repo, setting both `--insecure-skip-server-verification` (passed to Helm as `--insecure-skip-tls-verify`) and `--insecure-oci-force-http` (passed to Helm as `--plain-http`) causes Helm v4 to silently drop `--plain-http`, as `--insecure-skip-tls-verify` takes internal precedence. Plain HTTP registry operations then fail with `http: server gave HTTP response to HTTPS client`. This affects:
|
||||
|
||||
- Argo CD repos with `type=helm` with `--enable-oci`: having both flags on the same repo causes the chart pull to fail.
|
||||
- Argo CD repos with `type=oci` and `type=helm` with dependencies: `--insecure-skip-server-verification` on the main repo combined with `--insecure-oci-force-http` on any dependency repo causes dependency build to fail.
|
||||
|
||||
There is no workaround when both configurations are legitimately required in the same chain.
|
||||
|
||||
#### Applications with spec.source.helm.version setting
|
||||
|
||||
If you historically have the following setting on your Helm application, the setting is ignored and Argo CD will use Helm v4 only to render your charts:
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
source:
|
||||
helm:
|
||||
version: v3
|
||||
```
|
||||
|
||||
You are not required to update or remove this field, and can leave this setting as is.
|
||||
|
||||
### UI extensions must externalize `react/jsx-runtime`
|
||||
|
||||
The Argo CD UI was upgraded from React 16 to React 19 in 3.5. UI extensions built against an older Argo CD UI may fail to load with a `TypeError` until they are rebuilt to externalize `react/jsx-runtime`.
|
||||
@@ -130,6 +171,8 @@ Consume structured result from `sourceIntegrityResult` field instead.
|
||||
|
||||
## Helm Upgraded
|
||||
|
||||
Helm was upgraded to `4.2.0`, resulting in some breaking changes described in the `Breaking changes` section of this doc.
|
||||
|
||||
## Custom Healthchecks Added
|
||||
|
||||
## Other Changes
|
||||
|
||||
@@ -56,6 +56,7 @@ argocd repocreds add REPOURL [flags]
|
||||
--github-app-installation-id int installation id of the GitHub Application (optional, will be auto-discovered if not provided)
|
||||
--github-app-private-key-path string private key of the GitHub Application
|
||||
-h, --help help for add
|
||||
--insecure-oci-force-http Use http when accessing an OCI repository
|
||||
--password string password to the repository
|
||||
--proxy-url string If provided, this URL will be used to connect via proxy
|
||||
--ssh-private-key-path string path to the private ssh key (e.g. ~/.ssh/id_rsa)
|
||||
|
||||
@@ -689,18 +689,14 @@ repoServer:
|
||||
chmod -R 777 $HELM_DATA_HOME;
|
||||
```
|
||||
|
||||
## Helm Version
|
||||
## Helm Version
|
||||
|
||||
Argo CD will assume that the Helm chart is v3 (even if the apiVersion field in the chart is Helm v2), unless v2 is explicitly specified within the Argo CD Application (see below).
|
||||
This field was used in the past, during the transition period from Helm 2 to Helm 3.
|
||||
Before Helm 2 became EOL, Argo CD was shipped with both Helm binaries (v2 and v3) and users could specify which Helm binary Argo CD should use to render their charts, by setting this field.
|
||||
|
||||
If needed, it is possible to specifically set the Helm version to template with by setting the `helm-version` flag on the cli (either v2 or v3):
|
||||
|
||||
```bash
|
||||
argocd app set helm-guestbook --helm-version v3
|
||||
```
|
||||
|
||||
Or using declarative syntax:
|
||||
Since Helm 2 became EOL, this field does not need to be configured anymore. It exists for backwards-compatibility only. The only Helm binary used to render charts in Argo CD (starting with version 3.5) is v4.
|
||||
|
||||
If you historically have the following setting on your Helm applications:
|
||||
```yaml
|
||||
spec:
|
||||
source:
|
||||
@@ -708,6 +704,9 @@ spec:
|
||||
version: v3
|
||||
```
|
||||
|
||||
you are not required to update or remove this field, and can leave this setting as is.
|
||||
|
||||
|
||||
## Helm `--pass-credentials`
|
||||
|
||||
Helm, [starting with v3.6.1](https://github.com/helm/helm/releases/tag/v3.6.1),
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
1376ea697140e4db316736e760d5a47d12afc1524dce704476ef06fd7fdeddc6 helm-v4.2.0-darwin-amd64.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
f13f959015447b6bc309f9fd506509926543988a39035c088b52522ec95e2acb helm-v4.2.0-darwin-arm64.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
97dbeb971be4ac4b27e3839976d9564c0fb35c6f3b1da89dd1e292d236af4096 helm-v4.2.0-linux-amd64.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
1f8de130dfbd04de64978e7b852a7a547be1404956a366608276d2520b678670 helm-v4.2.0-linux-arm64.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
48f0637b93247717b725e8d4a8d2cf8df0e2fdea91bdd0e36e2426c2d5c76e4e helm-v4.2.0-linux-ppc64le.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
328e9ed27904f9910026240c4311bb1b0bf91c6fde1634f212097694507a702f helm-v4.2.0-linux-s390x.tar.gz
|
||||
@@ -3,9 +3,9 @@ set -eux -o pipefail
|
||||
|
||||
. "$(dirname "$0")"/../tool-versions.sh
|
||||
|
||||
export TARGET_FILE=helm-v${helm3_version}-${INSTALL_OS}-${ARCHITECTURE}.tar.gz
|
||||
export TARGET_FILE=helm-v${helm4_version}-${INSTALL_OS}-${ARCHITECTURE}.tar.gz
|
||||
|
||||
[ -e "$DOWNLOADS/${TARGET_FILE}" ] || curl -sLf --retry 3 -o "$DOWNLOADS/${TARGET_FILE}" "https://get.helm.sh/helm-v${helm3_version}-$INSTALL_OS-$ARCHITECTURE.tar.gz"
|
||||
[ -e "$DOWNLOADS/${TARGET_FILE}" ] || curl -sLf --retry 3 -o "$DOWNLOADS/${TARGET_FILE}" "https://get.helm.sh/helm-v${helm4_version}-$INSTALL_OS-$ARCHITECTURE.tar.gz"
|
||||
"$(dirname "$0")"/compare-chksum.sh
|
||||
mkdir -p /tmp/helm && tar -C /tmp/helm -xf "$DOWNLOADS/${TARGET_FILE}"
|
||||
sudo install -m 0755 "/tmp/helm/$INSTALL_OS-$ARCHITECTURE/helm" "$BIN/helm"
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
# Use ./hack/installers/checksums/add-helm-checksums.sh and
|
||||
# add-kustomize-checksums.sh to help download checksums.
|
||||
###############################################################################
|
||||
helm3_version=3.21.0
|
||||
helm4_version=4.2.0
|
||||
kustomize5_version=5.8.1
|
||||
protoc_version=29.3
|
||||
oras_version=1.2.0
|
||||
|
||||
@@ -13,6 +13,7 @@ metadata:
|
||||
app: argocd-redis-ha
|
||||
secrets:
|
||||
- name: argocd-redis
|
||||
|
||||
---
|
||||
# Source: redis-ha/charts/redis-ha/templates/redis-haproxy-serviceaccount.yaml
|
||||
apiVersion: v1
|
||||
@@ -25,6 +26,7 @@ metadata:
|
||||
release: argocd
|
||||
chart: redis-ha-4.35.10
|
||||
app: argocd-redis-ha
|
||||
|
||||
---
|
||||
# Source: redis-ha/charts/redis-ha/templates/redis-ha-configmap.yaml
|
||||
apiVersion: v1
|
||||
@@ -846,6 +848,7 @@ data:
|
||||
done
|
||||
echo "Failover successful"
|
||||
fi
|
||||
|
||||
---
|
||||
# Source: redis-ha/charts/redis-ha/templates/redis-ha-health-configmap.yaml
|
||||
apiVersion: v1
|
||||
@@ -921,6 +924,7 @@ data:
|
||||
exit 1
|
||||
fi
|
||||
echo "response=$response"
|
||||
|
||||
---
|
||||
# Source: redis-ha/charts/redis-ha/templates/redis-ha-role.yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
@@ -940,6 +944,7 @@ rules:
|
||||
- endpoints
|
||||
verbs:
|
||||
- get
|
||||
|
||||
---
|
||||
# Source: redis-ha/charts/redis-ha/templates/redis-haproxy-role.yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
@@ -960,6 +965,7 @@ rules:
|
||||
- endpoints
|
||||
verbs:
|
||||
- get
|
||||
|
||||
---
|
||||
# Source: redis-ha/charts/redis-ha/templates/redis-ha-rolebinding.yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
@@ -979,6 +985,7 @@ roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: argocd-redis-ha
|
||||
|
||||
---
|
||||
# Source: redis-ha/charts/redis-ha/templates/redis-haproxy-rolebinding.yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
@@ -999,6 +1006,7 @@ roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: argocd-redis-ha-haproxy
|
||||
|
||||
---
|
||||
# Source: redis-ha/charts/redis-ha/templates/redis-ha-announce-service.yaml
|
||||
apiVersion: v1
|
||||
@@ -1086,6 +1094,7 @@ spec:
|
||||
release: argocd
|
||||
app: redis-ha
|
||||
"statefulset.kubernetes.io/pod-name": argocd-redis-ha-server-2
|
||||
|
||||
---
|
||||
# Source: redis-ha/charts/redis-ha/templates/redis-ha-service.yaml
|
||||
apiVersion: v1
|
||||
@@ -1114,6 +1123,7 @@ spec:
|
||||
selector:
|
||||
release: argocd
|
||||
app: redis-ha
|
||||
|
||||
---
|
||||
# Source: redis-ha/charts/redis-ha/templates/redis-haproxy-service.yaml
|
||||
apiVersion: v1
|
||||
@@ -1142,6 +1152,7 @@ spec:
|
||||
selector:
|
||||
release: argocd
|
||||
app: redis-ha-haproxy
|
||||
|
||||
---
|
||||
# Source: redis-ha/charts/redis-ha/templates/redis-haproxy-deployment.yaml
|
||||
kind: Deployment
|
||||
@@ -1279,6 +1290,7 @@ spec:
|
||||
- name: data
|
||||
emptyDir:
|
||||
{}
|
||||
|
||||
---
|
||||
# Source: redis-ha/charts/redis-ha/templates/redis-ha-statefulset.yaml
|
||||
apiVersion: apps/v1
|
||||
|
||||
@@ -1140,6 +1140,7 @@ func getHelmRepos(appPath string, repositories []*v1alpha1.Repository, helmRepoC
|
||||
repo.TLSClientCertData = repositoryCredential.TLSClientCertData
|
||||
repo.TLSClientCertKey = repositoryCredential.TLSClientCertKey
|
||||
repo.UseAzureWorkloadIdentity = repositoryCredential.UseAzureWorkloadIdentity
|
||||
repo.InsecureOCIForceHttp = repositoryCredential.InsecureOCIForceHttp
|
||||
} else if repo.EnableOCI {
|
||||
// finally if repo is OCI and no credentials found, use the first OCI credential matching by hostname
|
||||
// see https://github.com/argoproj/argo-cd/issues/14636
|
||||
@@ -1154,12 +1155,13 @@ func getHelmRepos(appPath string, repositories []*v1alpha1.Repository, helmRepoC
|
||||
repo.Password = cred.Password
|
||||
repo.UseAzureWorkloadIdentity = cred.UseAzureWorkloadIdentity
|
||||
repo.EnableOCI = true
|
||||
repo.InsecureOCIForceHttp = cred.InsecureOCIForceHttp
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
repos = append(repos, helm.HelmRepository{Name: repo.Name, Repo: repo.Repo, Creds: repo.GetHelmCreds(), EnableOci: repo.EnableOCI})
|
||||
repos = append(repos, helm.HelmRepository{Name: repo.Name, Repo: repo.Repo, Creds: repo.GetHelmCreds(), EnableOci: repo.EnableOCI || repo.Type == "oci", InsecureOCIForceHttp: repo.InsecureOCIForceHttp})
|
||||
}
|
||||
return repos, nil
|
||||
}
|
||||
@@ -2879,7 +2881,11 @@ func (s *Service) newOCIClientResolveRevision(ctx context.Context, repo *v1alpha
|
||||
|
||||
func (s *Service) newHelmClientResolveRevision(repo *v1alpha1.Repository, revision string, chart string, noRevisionCache bool) (helm.Client, string, error) {
|
||||
enableOCI := repo.EnableOCI || helm.IsHelmOciRepo(repo.Repo)
|
||||
helmClient := s.newHelmClient(repo.Repo, repo.GetHelmCreds(), enableOCI, repo.Proxy, repo.NoProxy, helm.WithIndexCache(s.cache), helm.WithChartPaths(s.chartPaths))
|
||||
opts := []helm.ClientOpts{helm.WithIndexCache(s.cache), helm.WithChartPaths(s.chartPaths)}
|
||||
if repo.InsecureOCIForceHttp {
|
||||
opts = append(opts, helm.WithPlainHTTP())
|
||||
}
|
||||
helmClient := s.newHelmClient(repo.Repo, repo.GetHelmCreds(), enableOCI, repo.Proxy, repo.NoProxy, opts...)
|
||||
|
||||
// Note: This check runs the risk of returning a version which is not found in the helm registry.
|
||||
if versions.IsVersion(revision) {
|
||||
@@ -3084,7 +3090,11 @@ func (s *Service) TestRepository(ctx context.Context, q *apiclient.TestRepositor
|
||||
if !helm.IsHelmOciRepo(repo.Repo) {
|
||||
return errors.New("OCI Helm repository URL should include hostname and port only")
|
||||
}
|
||||
_, err := helm.NewClient(repo.Repo, repo.GetHelmCreds(), repo.EnableOCI, repo.Proxy, repo.NoProxy).TestHelmOCI()
|
||||
clientOpts := []helm.ClientOpts{}
|
||||
if repo.InsecureOCIForceHttp {
|
||||
clientOpts = append(clientOpts, helm.WithPlainHTTP())
|
||||
}
|
||||
_, err := helm.NewClient(repo.Repo, repo.GetHelmCreds(), repo.EnableOCI, repo.Proxy, repo.NoProxy, clientOpts...).TestHelmOCI()
|
||||
return err
|
||||
}
|
||||
_, err := helm.NewClient(repo.Repo, repo.GetHelmCreds(), repo.EnableOCI, repo.Proxy, repo.NoProxy).GetIndex(false, s.initConstants.HelmRegistryMaxIndexSize)
|
||||
|
||||
@@ -5894,3 +5894,41 @@ func TestGenerateManifest_OCISourceSkipsGitClient(t *testing.T) {
|
||||
// verify that newGitClient was never invoked
|
||||
assert.False(t, gitCalled, "GenerateManifest should not invoke Git for OCI sources")
|
||||
}
|
||||
|
||||
func TestGetHelmRepos_InsecureOCIForceHttpPropagatedFromRepo(t *testing.T) {
|
||||
q := apiclient.ManifestRequest{
|
||||
Repos: []*v1alpha1.Repository{{
|
||||
Repo: "oci://example.com",
|
||||
Username: "test",
|
||||
Password: "test",
|
||||
Type: "oci",
|
||||
InsecureOCIForceHttp: true,
|
||||
}},
|
||||
HelmRepoCreds: []*v1alpha1.RepoCreds{},
|
||||
}
|
||||
|
||||
helmRepos, err := getHelmRepos("./testdata/oci-dependencies", q.Repos, q.HelmRepoCreds)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Len(t, helmRepos, 1)
|
||||
assert.True(t, helmRepos[0].InsecureOCIForceHttp)
|
||||
}
|
||||
|
||||
func TestGetHelmRepos_InsecureOCIForceHttpPropagatedFromRepoCreds(t *testing.T) {
|
||||
q := apiclient.ManifestRequest{
|
||||
Repos: []*v1alpha1.Repository{},
|
||||
HelmRepoCreds: []*v1alpha1.RepoCreds{{
|
||||
URL: "oci://example.com",
|
||||
Username: "test",
|
||||
Password: "test",
|
||||
Type: "oci",
|
||||
InsecureOCIForceHttp: true,
|
||||
}},
|
||||
}
|
||||
|
||||
helmRepos, err := getHelmRepos("./testdata/oci-dependencies", q.Repos, q.HelmRepoCreds)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Len(t, helmRepos, 1)
|
||||
assert.True(t, helmRepos[0].InsecureOCIForceHttp)
|
||||
}
|
||||
|
||||
@@ -156,6 +156,7 @@ func AddHelmOCIRepo(t *testing.T, name string) {
|
||||
"--type", "helm",
|
||||
"--name", name,
|
||||
"--enable-oci",
|
||||
"--insecure-oci-force-http",
|
||||
}
|
||||
errors.NewHandler(t).FailOnErr(fixture.RunCli(args...))
|
||||
}
|
||||
@@ -212,7 +213,7 @@ func AddHelmoOCICredentialsWithoutUserPass(t *testing.T) {
|
||||
t.Helper()
|
||||
args := []string{
|
||||
"repocreds", "add", fixture.RepoURL(fixture.RepoURLTypeHelmOCI),
|
||||
"--enable-oci", "--type", "helm",
|
||||
"--enable-oci", "--type", "helm", "--insecure-oci-force-http",
|
||||
}
|
||||
errors.NewHandler(t).FailOnErr(fixture.RunCli(args...))
|
||||
}
|
||||
@@ -238,13 +239,14 @@ func PushChartToOCIRegistry(t *testing.T, chartPathName, chartName, chartVersion
|
||||
chartAbsPath, err2 := filepath.Abs("./" + chartPathName)
|
||||
require.NoError(t, err2)
|
||||
|
||||
errors.NewHandler(t).FailOnErr(fixture.Run("", "helm", "dependency", "build", chartAbsPath))
|
||||
errors.NewHandler(t).FailOnErr(fixture.Run("", "helm", "dependency", "build", "--plain-http", chartAbsPath))
|
||||
errors.NewHandler(t).FailOnErr(fixture.Run("", "helm", "package", chartAbsPath, "--destination", tempDest))
|
||||
_ = os.RemoveAll(fmt.Sprintf("%s/%s", chartAbsPath, "charts"))
|
||||
errors.NewHandler(t).FailOnErr(fixture.Run(
|
||||
"",
|
||||
"helm",
|
||||
"push",
|
||||
"--plain-http",
|
||||
fmt.Sprintf("%s/%s-%s.tgz", tempDest, chartName, chartVersion),
|
||||
"oci://"+fixture.HelmOCIRegistryURL,
|
||||
))
|
||||
@@ -261,7 +263,7 @@ func PushChartToAuthenticatedOCIRegistry(t *testing.T, chartPathName, chartName,
|
||||
chartAbsPath, err2 := filepath.Abs("./" + chartPathName)
|
||||
require.NoError(t, err2)
|
||||
|
||||
errors.NewHandler(t).FailOnErr(fixture.Run("", "helm", "dependency", "build", chartAbsPath))
|
||||
errors.NewHandler(t).FailOnErr(fixture.Run("", "helm", "dependency", "build", "--plain-http", chartAbsPath))
|
||||
errors.NewHandler(t).FailOnErr(fixture.Run("", "helm", "package", chartAbsPath, "--destination", tempDest))
|
||||
_ = os.RemoveAll(fmt.Sprintf("%s/%s", chartAbsPath, "charts"))
|
||||
|
||||
@@ -270,6 +272,7 @@ func PushChartToAuthenticatedOCIRegistry(t *testing.T, chartPathName, chartName,
|
||||
"helm",
|
||||
"registry",
|
||||
"login",
|
||||
"--plain-http",
|
||||
"--username", fixture.GitUsername,
|
||||
"--password", fixture.GitPassword,
|
||||
"localhost:5001",
|
||||
@@ -279,6 +282,7 @@ func PushChartToAuthenticatedOCIRegistry(t *testing.T, chartPathName, chartName,
|
||||
"",
|
||||
"helm",
|
||||
"push",
|
||||
"--plain-http",
|
||||
fmt.Sprintf("%s/%s-%s.tgz", tempDest, chartName, chartVersion),
|
||||
"oci://"+fixture.HelmAuthenticatedOCIRegistryURL,
|
||||
))
|
||||
|
||||
@@ -676,3 +676,21 @@ func TestTemplatesHelmOCIWithDependencies(t *testing.T) {
|
||||
Expect(HealthIs(health.HealthStatusHealthy)).
|
||||
Expect(SyncStatusIs(SyncStatusCodeSynced))
|
||||
}
|
||||
|
||||
func TestHelmOCIRegistryWithConstraintRevision(t *testing.T) {
|
||||
Given(t).
|
||||
PushChartToOCIRegistry("testdata/helm-values", "helm-values", "1.0.0").
|
||||
HelmOCIRepoAdded("myrepo").
|
||||
RepoURLType(fixture.RepoURLTypeHelmOCI).
|
||||
Chart("helm-values").
|
||||
Revision(">=1.0.0").
|
||||
When().
|
||||
CreateApp().
|
||||
Then().
|
||||
When().
|
||||
Sync().
|
||||
Then().
|
||||
Expect(OperationPhaseIs(OperationSucceeded)).
|
||||
Expect(HealthIs(health.HealthStatusHealthy)).
|
||||
Expect(SyncStatusIs(SyncStatusCodeSynced))
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ func TestOCIWithOCIHelmRegistryDependencies(t *testing.T) {
|
||||
PushImageToOCIRegistry("testdata/helm-oci-with-dependencies", "1.0.0").
|
||||
OCIRegistry(fixture.OCIHostURL).
|
||||
OCIRepoAdded("helm-oci-with-dependencies", "helm-oci-with-dependencies").
|
||||
OCIRepoAdded("helm-values", "myrepo").
|
||||
OCIRegistryPath("helm-oci-with-dependencies").
|
||||
Revision("1.0.0").
|
||||
Path(".").
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
export HELM_EXPERIMENTAL_OCI=1
|
||||
docker run -p 5001:5000 --rm --name authed-registry -v "$(pwd)"/test/fixture/testrepos/.oci-htpasswd:/etc/docker/registry/auth.htpasswd \
|
||||
-e REGISTRY_AUTH="{htpasswd: {realm: localhost, path: /etc/docker/registry/auth.htpasswd}}" \
|
||||
registry
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
#!/usr/bin/env bash
|
||||
export HELM_EXPERIMENTAL_OCI=1
|
||||
docker run -p 5000:5000 --rm --name registry registry
|
||||
|
||||
+12
-3
@@ -88,6 +88,13 @@ func WithUserAgent(userAgent string) ClientOpts {
|
||||
}
|
||||
}
|
||||
|
||||
// WithPlainHTTP configures the client to use plain HTTP instead of HTTPS for OCI registry operations.
|
||||
func WithPlainHTTP() ClientOpts {
|
||||
return func(c *nativeHelmChart) {
|
||||
c.plainHTTP = true
|
||||
}
|
||||
}
|
||||
|
||||
func NewClient(repoURL string, creds Creds, enableOci bool, proxy string, noProxy string, opts ...ClientOpts) Client {
|
||||
return NewClientWithLock(repoURL, creds, globalLock, enableOci, proxy, noProxy, opts...)
|
||||
}
|
||||
@@ -116,6 +123,7 @@ type nativeHelmChart struct {
|
||||
creds Creds
|
||||
repoLock sync.KeyLock
|
||||
enableOci bool
|
||||
plainHTTP bool
|
||||
indexCache indexCache
|
||||
proxy string
|
||||
noProxy string
|
||||
@@ -217,7 +225,7 @@ func (c *nativeHelmChart) ExtractChart(chart string, version string, passCredent
|
||||
return "", nil, fmt.Errorf("failed to get password for helm registry: %w", err)
|
||||
}
|
||||
if helmPassword != "" && c.creds.GetUsername() != "" {
|
||||
_, err = helmCmd.RegistryLogin(c.repoURL, c.creds)
|
||||
_, err = helmCmd.RegistryLogin(c.repoURL, c.creds, c.plainHTTP)
|
||||
if err != nil {
|
||||
_ = os.RemoveAll(tempDir)
|
||||
return "", nil, fmt.Errorf("error logging into OCI registry: %w", err)
|
||||
@@ -229,7 +237,7 @@ func (c *nativeHelmChart) ExtractChart(chart string, version string, passCredent
|
||||
}
|
||||
|
||||
// 'helm pull' ensures that chart is downloaded into temp directory
|
||||
_, err = helmCmd.PullOCI(c.repoURL, chart, version, tempDest, c.creds)
|
||||
_, err = helmCmd.PullOCI(c.repoURL, chart, version, tempDest, c.creds, c.plainHTTP)
|
||||
if err != nil {
|
||||
_ = os.RemoveAll(tempDir)
|
||||
return "", nil, fmt.Errorf("error pulling OCI chart: %w", err)
|
||||
@@ -328,7 +336,7 @@ func (c *nativeHelmChart) TestHelmOCI() (bool, error) {
|
||||
return false, fmt.Errorf("failed to get password for helm registry: %w", err)
|
||||
}
|
||||
if c.creds.GetUsername() != "" && helmPassword != "" {
|
||||
_, err = helmCmd.RegistryLogin(c.repoURL, c.creds)
|
||||
_, err = helmCmd.RegistryLogin(c.repoURL, c.creds, c.plainHTTP)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("error logging into OCI registry: %w", err)
|
||||
}
|
||||
@@ -483,6 +491,7 @@ func (c *nativeHelmChart) GetTags(chart string, noCache bool) ([]string, error)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to initialize repository: %w", err)
|
||||
}
|
||||
repo.PlainHTTP = c.plainHTTP
|
||||
tlsConf, err := newTLSConfig(c.creds)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed setup tlsConfig: %w", err)
|
||||
|
||||
@@ -769,3 +769,15 @@ entries: {}
|
||||
t.Logf("Default User-Agent sent: %s", receivedUserAgent)
|
||||
})
|
||||
}
|
||||
|
||||
func TestWithPlainHTTP(t *testing.T) {
|
||||
t.Run("not set by default", func(t *testing.T) {
|
||||
c := NewClient("my.registry.com", HelmCreds{}, true, "", "")
|
||||
assert.False(t, c.(*nativeHelmChart).plainHTTP)
|
||||
})
|
||||
|
||||
t.Run("set via WithPlainHTTP option", func(t *testing.T) {
|
||||
c := NewClient("my.registry.com", HelmCreds{}, true, "", "", WithPlainHTTP())
|
||||
assert.True(t, c.(*nativeHelmChart).plainHTTP)
|
||||
})
|
||||
}
|
||||
|
||||
+20
-6
@@ -34,11 +34,16 @@ type Cmd struct {
|
||||
|
||||
func NewCmd(workDir string, version string, proxy string, noProxy string) (*Cmd, error) {
|
||||
switch version {
|
||||
// If v3 is specified (or by default, if no value is specified) then use v3
|
||||
case "", "v3":
|
||||
// There was a point in time when we supported both v2 and v3, and at some point we stopped
|
||||
// supporting v2.
|
||||
// We now support v4 only, but from Helm docs v4 is backwards compatible with v3 charts.
|
||||
// Removing the v3 value would break existing applications that specify v3.
|
||||
// There is also no reason for users to specify v4 explicitly, but in case someone does it, we support the value.
|
||||
// TODO: Remove support for v3 value in a major release.
|
||||
case "", "v3", "v4":
|
||||
return NewCmdWithVersion(workDir, false, proxy, noProxy)
|
||||
}
|
||||
return nil, fmt.Errorf("helm chart version '%s' is not supported", version)
|
||||
return nil, fmt.Errorf("helm version '%s' is not supported", version)
|
||||
}
|
||||
|
||||
func NewCmdWithVersion(workDir string, isHelmOci bool, proxy string, noProxy string) (*Cmd, error) {
|
||||
@@ -79,13 +84,16 @@ func (c Cmd) run(ctx context.Context, args ...string) (string, string, error) {
|
||||
return out, fullCommand, nil
|
||||
}
|
||||
|
||||
func (c *Cmd) RegistryLogin(repo string, creds Creds) (string, error) {
|
||||
func (c *Cmd) RegistryLogin(repo string, creds Creds, plainHTTP bool) (string, error) {
|
||||
args := []string{"registry", "login"}
|
||||
registry, err := c.getHelmRegistry(repo)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to parse registry URL: %w", err)
|
||||
}
|
||||
args = append(args, registry)
|
||||
if plainHTTP {
|
||||
args = append(args, "--plain-http")
|
||||
}
|
||||
|
||||
if creds.GetUsername() != "" {
|
||||
args = append(args, "--username", creds.GetUsername())
|
||||
@@ -288,7 +296,7 @@ func (c *Cmd) Fetch(repo, chartName, version, destination string, creds Creds, p
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *Cmd) PullOCI(repo string, chart string, version string, destination string, creds Creds) (string, error) {
|
||||
func (c *Cmd) PullOCI(repo string, chart string, version string, destination string, creds Creds, plainHTTP bool) (string, error) {
|
||||
args := []string{
|
||||
"pull", fmt.Sprintf("oci://%s/%s", repo, chart), "--version",
|
||||
version,
|
||||
@@ -320,6 +328,9 @@ func (c *Cmd) PullOCI(repo string, chart string, version string, destination str
|
||||
if creds.GetInsecureSkipVerify() {
|
||||
args = append(args, "--insecure-skip-tls-verify")
|
||||
}
|
||||
if plainHTTP {
|
||||
args = append(args, "--plain-http")
|
||||
}
|
||||
out, _, err := c.run(context.Background(), args...)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to pull OCI chart: %w", err)
|
||||
@@ -327,11 +338,14 @@ func (c *Cmd) PullOCI(repo string, chart string, version string, destination str
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *Cmd) dependencyBuild(insecure bool) (string, error) {
|
||||
func (c *Cmd) dependencyBuild(insecure bool, plainHTTP bool) (string, error) {
|
||||
args := []string{"dependency", "build"}
|
||||
if insecure {
|
||||
args = append(args, "--insecure-skip-tls-verify")
|
||||
}
|
||||
if plainHTTP {
|
||||
args = append(args, "--plain-http")
|
||||
}
|
||||
out, _, err := c.run(context.Background(), args...)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to build dependencies: %w", err)
|
||||
|
||||
+86
-11
@@ -42,7 +42,7 @@ func TestCmd_template_noApiVersionsInError(t *testing.T) {
|
||||
func TestNewCmd_helmInvalidVersion(t *testing.T) {
|
||||
_, err := NewCmd(".", "abcd", "", "")
|
||||
log.Println(err)
|
||||
assert.EqualError(t, err, "helm chart version 'abcd' is not supported")
|
||||
assert.EqualError(t, err, "helm version 'abcd' is not supported")
|
||||
}
|
||||
|
||||
func TestNewCmd_withProxy(t *testing.T) {
|
||||
@@ -57,6 +57,7 @@ func TestRegistryLogin(t *testing.T) {
|
||||
name string
|
||||
repo string
|
||||
creds *HelmCreds
|
||||
plainHTTP bool
|
||||
execErr error
|
||||
expectedErr error
|
||||
expectedOut string
|
||||
@@ -114,6 +115,20 @@ func TestRegistryLogin(t *testing.T) {
|
||||
},
|
||||
expectedOut: "helm registry login my.registry.com:5000 --username u --password p --ca-file /ca --insecure",
|
||||
},
|
||||
{
|
||||
name: "plain-http",
|
||||
repo: "my.registry.com/repo",
|
||||
creds: &HelmCreds{Username: "user", Password: "pass"},
|
||||
plainHTTP: true,
|
||||
expectedOut: "helm registry login my.registry.com --plain-http --username user --password pass",
|
||||
},
|
||||
{
|
||||
name: "insecure and plain-http both set",
|
||||
repo: "my.registry.com/repo",
|
||||
creds: &HelmCreds{InsecureSkipVerify: true},
|
||||
plainHTTP: true,
|
||||
expectedOut: "helm registry login my.registry.com --plain-http --insecure",
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
@@ -124,7 +139,7 @@ func TestRegistryLogin(t *testing.T) {
|
||||
return strings.Join(cmd.Args, " "), nil
|
||||
})
|
||||
require.NoError(t, err)
|
||||
out, err := c.RegistryLogin(tc.repo, tc.creds)
|
||||
out, err := c.RegistryLogin(tc.repo, tc.creds, tc.plainHTTP)
|
||||
assert.Equal(t, tc.expectedOut, out)
|
||||
if tc.expectedErr != nil {
|
||||
require.EqualError(t, err, tc.expectedErr.Error())
|
||||
@@ -135,21 +150,36 @@ func TestRegistryLogin(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDependencyBuild(t *testing.T) {
|
||||
func TestPullOCI(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
insecure bool
|
||||
creds HelmCreds
|
||||
plainHTTP bool
|
||||
expectedOut string
|
||||
}{
|
||||
{
|
||||
name: "without insecure",
|
||||
insecure: false,
|
||||
expectedOut: "helm dependency build",
|
||||
name: "without flags",
|
||||
creds: HelmCreds{},
|
||||
plainHTTP: false,
|
||||
expectedOut: "helm pull oci://my.registry.com/myrepo/mychart --version 1.0.0 --destination /tmp/dest",
|
||||
},
|
||||
{
|
||||
name: "with insecure",
|
||||
insecure: true,
|
||||
expectedOut: "helm dependency build --insecure-skip-tls-verify",
|
||||
name: "insecure skip verify",
|
||||
creds: HelmCreds{InsecureSkipVerify: true},
|
||||
plainHTTP: false,
|
||||
expectedOut: "helm pull oci://my.registry.com/myrepo/mychart --version 1.0.0 --destination /tmp/dest --insecure-skip-tls-verify",
|
||||
},
|
||||
{
|
||||
name: "plain-http",
|
||||
creds: HelmCreds{},
|
||||
plainHTTP: true,
|
||||
expectedOut: "helm pull oci://my.registry.com/myrepo/mychart --version 1.0.0 --destination /tmp/dest --plain-http",
|
||||
},
|
||||
{
|
||||
name: "insecure and plain-http both set",
|
||||
creds: HelmCreds{InsecureSkipVerify: true},
|
||||
plainHTTP: true,
|
||||
expectedOut: "helm pull oci://my.registry.com/myrepo/mychart --version 1.0.0 --destination /tmp/dest --insecure-skip-tls-verify --plain-http",
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
@@ -158,7 +188,52 @@ func TestDependencyBuild(t *testing.T) {
|
||||
return strings.Join(cmd.Args, " "), nil
|
||||
})
|
||||
require.NoError(t, err)
|
||||
out, err := c.dependencyBuild(tc.insecure)
|
||||
out, err := c.PullOCI("my.registry.com/myrepo", "mychart", "1.0.0", "/tmp/dest", &tc.creds, tc.plainHTTP)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tc.expectedOut, out)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDependencyBuild(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
insecure bool
|
||||
plainHTTP bool
|
||||
expectedOut string
|
||||
}{
|
||||
{
|
||||
name: "without flags",
|
||||
insecure: false,
|
||||
plainHTTP: false,
|
||||
expectedOut: "helm dependency build",
|
||||
},
|
||||
{
|
||||
name: "with insecure",
|
||||
insecure: true,
|
||||
plainHTTP: false,
|
||||
expectedOut: "helm dependency build --insecure-skip-tls-verify",
|
||||
},
|
||||
{
|
||||
name: "with plain-http",
|
||||
insecure: false,
|
||||
plainHTTP: true,
|
||||
expectedOut: "helm dependency build --plain-http",
|
||||
},
|
||||
{
|
||||
name: "with insecure and plain-http both set",
|
||||
insecure: true,
|
||||
plainHTTP: true,
|
||||
expectedOut: "helm dependency build --insecure-skip-tls-verify --plain-http",
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
c, err := newCmdWithVersion(".", false, "", "", func(cmd *exec.Cmd, _ func(_ string) string) (string, error) {
|
||||
return strings.Join(cmd.Args, " "), nil
|
||||
})
|
||||
require.NoError(t, err)
|
||||
out, err := c.dependencyBuild(tc.insecure, tc.plainHTTP)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tc.expectedOut, out)
|
||||
})
|
||||
|
||||
+18
-5
@@ -25,9 +25,10 @@ const (
|
||||
|
||||
type HelmRepository struct {
|
||||
Creds
|
||||
Name string
|
||||
Repo string
|
||||
EnableOci bool
|
||||
Name string
|
||||
Repo string
|
||||
EnableOci bool
|
||||
InsecureOCIForceHttp bool
|
||||
}
|
||||
|
||||
// Helm provides wrapper functionality around the `helm` command.
|
||||
@@ -91,7 +92,7 @@ func (h *helm) DependencyBuild() error {
|
||||
return fmt.Errorf("failed to get password for helm registry: %w", err)
|
||||
}
|
||||
if repo.GetUsername() != "" && helmPassword != "" {
|
||||
_, err := h.cmd.RegistryLogin(repo.Repo, repo.Creds)
|
||||
_, err := h.cmd.RegistryLogin(repo.Repo, repo.Creds, repo.InsecureOCIForceHttp)
|
||||
|
||||
defer func() {
|
||||
_, _ = h.cmd.RegistryLogout(repo.Repo, repo.Creds)
|
||||
@@ -108,8 +109,20 @@ func (h *helm) DependencyBuild() error {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if any dependent repository has insecureOCIForceHttp set to true
|
||||
// If so, set the command to use plain HTTP, as helm dependency build command doesn't support mixed TLS and non TLS dependencies
|
||||
// Please note that the fact we logged in earlier to each dependent repo with it's own InsecureOCIForceHttp either enabled or disabled
|
||||
// is unrelated to how we perform helm dependency build, which does not have an option to set --plain-http per repo
|
||||
plainHTTP := false
|
||||
for i := range h.repos {
|
||||
if h.repos[i].InsecureOCIForceHttp {
|
||||
plainHTTP = true
|
||||
break
|
||||
}
|
||||
}
|
||||
h.repos = nil
|
||||
_, err := h.cmd.dependencyBuild(h.insecure)
|
||||
_, err := h.cmd.dependencyBuild(h.insecure, plainHTTP)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to build helm dependencies: %w", err)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package helm
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -276,3 +278,64 @@ func TestSkipTests(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, objs)
|
||||
}
|
||||
|
||||
func TestDependencyBuild_PlainHTTPFromDependencyRepo(t *testing.T) {
|
||||
// dependency build has no per-repo --plain-http; if ANY dependency repo is
|
||||
// plain-http, the whole build must use --plain-http (see helm.DependencyBuild).
|
||||
tests := []struct {
|
||||
name string
|
||||
depInsecureHTTP []bool // one entry per dependency repo
|
||||
expectPlainHTTP bool
|
||||
}{
|
||||
{
|
||||
name: "single https dep — no plain-http",
|
||||
depInsecureHTTP: []bool{false},
|
||||
expectPlainHTTP: false,
|
||||
},
|
||||
{
|
||||
name: "single plain-http dep — plain-http",
|
||||
depInsecureHTTP: []bool{true},
|
||||
expectPlainHTTP: true,
|
||||
},
|
||||
{
|
||||
name: "mixed deps — any plain-http dep forces plain-http for the whole build",
|
||||
depInsecureHTTP: []bool{false, true},
|
||||
expectPlainHTTP: true,
|
||||
},
|
||||
{
|
||||
name: "all https deps — no plain-http",
|
||||
depInsecureHTTP: []bool{false, false},
|
||||
expectPlainHTTP: false,
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
var capturedArgs []string
|
||||
c, err := newCmdWithVersion(".", false, "", "", func(cmd *exec.Cmd, _ func(string) string) (string, error) {
|
||||
capturedArgs = cmd.Args
|
||||
return "", nil
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
repos := make([]HelmRepository, len(tc.depInsecureHTTP))
|
||||
for i, forceHTTP := range tc.depInsecureHTTP {
|
||||
repos[i] = HelmRepository{
|
||||
Repo: "oci://localhost:5000/myrepo",
|
||||
EnableOci: true,
|
||||
InsecureOCIForceHttp: forceHTTP,
|
||||
Creds: HelmCreds{},
|
||||
}
|
||||
}
|
||||
|
||||
h := &helm{
|
||||
cmd: *c,
|
||||
repos: repos,
|
||||
}
|
||||
|
||||
err = h.DependencyBuild()
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, tc.expectPlainHTTP, slices.Contains(capturedArgs, "--plain-http"))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user