github.com/argoproj/argo-cd/v2@v2.10.5/util/settings/settings_test.go (about)

     1  package settings
     2  
     3  import (
     4  	"context"
     5  	"crypto/tls"
     6  	"crypto/x509"
     7  	"fmt"
     8  	"sort"
     9  	"strings"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/argoproj/argo-cd/v2/common"
    14  	"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
    15  	testutil "github.com/argoproj/argo-cd/v2/test"
    16  	"github.com/argoproj/argo-cd/v2/util/test"
    17  
    18  	"github.com/stretchr/testify/assert"
    19  	"github.com/stretchr/testify/require"
    20  	v1 "k8s.io/api/core/v1"
    21  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    22  	"k8s.io/client-go/kubernetes/fake"
    23  )
    24  
    25  func fixtures(data map[string]string, opts ...func(secret *v1.Secret)) (*fake.Clientset, *SettingsManager) {
    26  	cm := &v1.ConfigMap{
    27  		ObjectMeta: metav1.ObjectMeta{
    28  			Name:      common.ArgoCDConfigMapName,
    29  			Namespace: "default",
    30  			Labels: map[string]string{
    31  				"app.kubernetes.io/part-of": "argocd",
    32  			},
    33  		},
    34  		Data: data,
    35  	}
    36  	secret := &v1.Secret{
    37  		ObjectMeta: metav1.ObjectMeta{
    38  			Name:      common.ArgoCDSecretName,
    39  			Namespace: "default",
    40  			Labels: map[string]string{
    41  				"app.kubernetes.io/part-of": "argocd",
    42  			},
    43  		},
    44  		Data: map[string][]byte{},
    45  	}
    46  	for i := range opts {
    47  		opts[i](secret)
    48  	}
    49  	kubeClient := fake.NewSimpleClientset(cm, secret)
    50  	settingsManager := NewSettingsManager(context.Background(), kubeClient, "default")
    51  
    52  	return kubeClient, settingsManager
    53  }
    54  
    55  func TestGetRepositories(t *testing.T) {
    56  	_, settingsManager := fixtures(map[string]string{
    57  		"repositories": "\n  - url: http://foo\n",
    58  	})
    59  	filter, err := settingsManager.GetRepositories()
    60  	assert.NoError(t, err)
    61  	assert.Equal(t, []Repository{{URL: "http://foo"}}, filter)
    62  }
    63  
    64  func TestSaveRepositories(t *testing.T) {
    65  	kubeClient, settingsManager := fixtures(nil)
    66  	err := settingsManager.SaveRepositories([]Repository{{URL: "http://foo"}})
    67  	assert.NoError(t, err)
    68  	cm, err := kubeClient.CoreV1().ConfigMaps("default").Get(context.Background(), common.ArgoCDConfigMapName, metav1.GetOptions{})
    69  	assert.NoError(t, err)
    70  	assert.Equal(t, cm.Data["repositories"], "- url: http://foo\n")
    71  
    72  	repos, err := settingsManager.GetRepositories()
    73  	assert.NoError(t, err)
    74  	assert.ElementsMatch(t, repos, []Repository{{URL: "http://foo"}})
    75  }
    76  
    77  func TestSaveRepositoriesNoConfigMap(t *testing.T) {
    78  	kubeClient := fake.NewSimpleClientset()
    79  	settingsManager := NewSettingsManager(context.Background(), kubeClient, "default")
    80  
    81  	err := settingsManager.SaveRepositories([]Repository{{URL: "http://foo"}})
    82  	assert.NoError(t, err)
    83  	cm, err := kubeClient.CoreV1().ConfigMaps("default").Get(context.Background(), common.ArgoCDConfigMapName, metav1.GetOptions{})
    84  	assert.NoError(t, err)
    85  	assert.Equal(t, cm.Data["repositories"], "- url: http://foo\n")
    86  }
    87  
    88  func TestSaveRepositoryCredentials(t *testing.T) {
    89  	kubeClient, settingsManager := fixtures(nil)
    90  	err := settingsManager.SaveRepositoryCredentials([]RepositoryCredentials{{URL: "http://foo"}})
    91  	assert.NoError(t, err)
    92  	cm, err := kubeClient.CoreV1().ConfigMaps("default").Get(context.Background(), common.ArgoCDConfigMapName, metav1.GetOptions{})
    93  	assert.NoError(t, err)
    94  	assert.Equal(t, cm.Data["repository.credentials"], "- url: http://foo\n")
    95  
    96  	creds, err := settingsManager.GetRepositoryCredentials()
    97  	assert.NoError(t, err)
    98  	assert.ElementsMatch(t, creds, []RepositoryCredentials{{URL: "http://foo"}})
    99  }
   100  
   101  func TestGetRepositoryCredentials(t *testing.T) {
   102  	_, settingsManager := fixtures(map[string]string{
   103  		"repository.credentials": "\n  - url: http://foo\n",
   104  	})
   105  	filter, err := settingsManager.GetRepositoryCredentials()
   106  	assert.NoError(t, err)
   107  	assert.Equal(t, []RepositoryCredentials{{URL: "http://foo"}}, filter)
   108  }
   109  
   110  func TestGetResourceFilter(t *testing.T) {
   111  	data := map[string]string{
   112  		"resource.exclusions": "\n  - apiGroups: [\"group1\"]\n    kinds: [\"kind1\"]\n    clusters: [\"cluster1\"]\n",
   113  		"resource.inclusions": "\n  - apiGroups: [\"group2\"]\n    kinds: [\"kind2\"]\n    clusters: [\"cluster2\"]\n",
   114  	}
   115  	_, settingsManager := fixtures(data)
   116  	filter, err := settingsManager.GetResourcesFilter()
   117  	assert.NoError(t, err)
   118  	assert.Equal(t, &ResourcesFilter{
   119  		ResourceExclusions: []FilteredResource{{APIGroups: []string{"group1"}, Kinds: []string{"kind1"}, Clusters: []string{"cluster1"}}},
   120  		ResourceInclusions: []FilteredResource{{APIGroups: []string{"group2"}, Kinds: []string{"kind2"}, Clusters: []string{"cluster2"}}},
   121  	}, filter)
   122  }
   123  
   124  func TestInClusterServerAddressEnabled(t *testing.T) {
   125  	_, settingsManager := fixtures(map[string]string{
   126  		"cluster.inClusterEnabled": "true",
   127  	})
   128  	argoCDCM, err := settingsManager.getConfigMap()
   129  	assert.NoError(t, err)
   130  	assert.Equal(t, true, argoCDCM.Data[inClusterEnabledKey] == "true")
   131  
   132  	_, settingsManager = fixtures(map[string]string{
   133  		"cluster.inClusterEnabled": "false",
   134  	})
   135  	argoCDCM, err = settingsManager.getConfigMap()
   136  	assert.NoError(t, err)
   137  	assert.Equal(t, false, argoCDCM.Data[inClusterEnabledKey] == "true")
   138  }
   139  
   140  func TestInClusterServerAddressEnabledByDefault(t *testing.T) {
   141  	kubeClient := fake.NewSimpleClientset(
   142  		&v1.ConfigMap{
   143  			ObjectMeta: metav1.ObjectMeta{
   144  				Name:      common.ArgoCDConfigMapName,
   145  				Namespace: "default",
   146  				Labels: map[string]string{
   147  					"app.kubernetes.io/part-of": "argocd",
   148  				},
   149  			},
   150  			Data: map[string]string{},
   151  		},
   152  		&v1.Secret{
   153  			ObjectMeta: metav1.ObjectMeta{
   154  				Name:      common.ArgoCDSecretName,
   155  				Namespace: "default",
   156  				Labels: map[string]string{
   157  					"app.kubernetes.io/part-of": "argocd",
   158  				},
   159  			},
   160  			Data: map[string][]byte{
   161  				"admin.password":   nil,
   162  				"server.secretkey": nil,
   163  			},
   164  		},
   165  	)
   166  	settingsManager := NewSettingsManager(context.Background(), kubeClient, "default")
   167  	settings, err := settingsManager.GetSettings()
   168  	assert.NoError(t, err)
   169  	assert.Equal(t, true, settings.InClusterEnabled)
   170  }
   171  
   172  func TestGetAppInstanceLabelKey(t *testing.T) {
   173  	_, settingsManager := fixtures(map[string]string{
   174  		"application.instanceLabelKey": "testLabel",
   175  	})
   176  	label, err := settingsManager.GetAppInstanceLabelKey()
   177  	assert.NoError(t, err)
   178  	assert.Equal(t, "testLabel", label)
   179  }
   180  
   181  func TestGetServerRBACLogEnforceEnableKeyDefaultFalse(t *testing.T) {
   182  	_, settingsManager := fixtures(nil)
   183  	serverRBACLogEnforceEnable, err := settingsManager.GetServerRBACLogEnforceEnable()
   184  	assert.NoError(t, err)
   185  	assert.Equal(t, false, serverRBACLogEnforceEnable)
   186  }
   187  
   188  func TestGetIsIgnoreResourceUpdatesEnabled(t *testing.T) {
   189  	_, settingsManager := fixtures(map[string]string{
   190  		"resource.ignoreResourceUpdatesEnabled": "true",
   191  	})
   192  	ignoreResourceUpdatesEnabled, err := settingsManager.GetIsIgnoreResourceUpdatesEnabled()
   193  	assert.NoError(t, err)
   194  	assert.True(t, ignoreResourceUpdatesEnabled)
   195  }
   196  
   197  func TestGetIsIgnoreResourceUpdatesEnabledDefaultFalse(t *testing.T) {
   198  	_, settingsManager := fixtures(nil)
   199  	ignoreResourceUpdatesEnabled, err := settingsManager.GetIsIgnoreResourceUpdatesEnabled()
   200  	assert.NoError(t, err)
   201  	assert.False(t, ignoreResourceUpdatesEnabled)
   202  }
   203  
   204  func TestGetServerRBACLogEnforceEnableKey(t *testing.T) {
   205  	_, settingsManager := fixtures(map[string]string{
   206  		"server.rbac.log.enforce.enable": "true",
   207  	})
   208  	serverRBACLogEnforceEnable, err := settingsManager.GetServerRBACLogEnforceEnable()
   209  	assert.NoError(t, err)
   210  	assert.Equal(t, true, serverRBACLogEnforceEnable)
   211  }
   212  
   213  func TestGetResourceOverrides(t *testing.T) {
   214  	ignoreStatus := v1alpha1.ResourceOverride{IgnoreDifferences: v1alpha1.OverrideIgnoreDiff{
   215  		JSONPointers: []string{"/status"},
   216  	}}
   217  	ignoreCRDFields := v1alpha1.ResourceOverride{IgnoreDifferences: v1alpha1.OverrideIgnoreDiff{
   218  		JSONPointers: []string{"/status", "/spec/preserveUnknownFields"},
   219  	}}
   220  	crdGK := "apiextensions.k8s.io/CustomResourceDefinition"
   221  
   222  	_, settingsManager := fixtures(map[string]string{
   223  		"resource.customizations": `
   224      admissionregistration.k8s.io/MutatingWebhookConfiguration:
   225        ignoreDifferences: |
   226          jsonPointers:
   227          - /webhooks/0/clientConfig/caBundle
   228          jqPathExpressions:
   229          - .webhooks[0].clientConfig.caBundle
   230        ignoreResourceUpdates: |
   231          jsonPointers:
   232          - /webhooks/1/clientConfig/caBundle
   233          jqPathExpressions:
   234          - .webhooks[1].clientConfig.caBundle`,
   235  	})
   236  	overrides, err := settingsManager.GetResourceOverrides()
   237  	assert.NoError(t, err)
   238  
   239  	webHookOverrides := overrides["admissionregistration.k8s.io/MutatingWebhookConfiguration"]
   240  	assert.NotNil(t, webHookOverrides)
   241  
   242  	assert.Equal(t, v1alpha1.ResourceOverride{
   243  		IgnoreDifferences: v1alpha1.OverrideIgnoreDiff{
   244  			JSONPointers:      []string{"/webhooks/0/clientConfig/caBundle"},
   245  			JQPathExpressions: []string{".webhooks[0].clientConfig.caBundle"},
   246  		},
   247  		IgnoreResourceUpdates: v1alpha1.OverrideIgnoreDiff{
   248  			JSONPointers:      []string{"/webhooks/1/clientConfig/caBundle"},
   249  			JQPathExpressions: []string{".webhooks[1].clientConfig.caBundle"},
   250  		},
   251  	}, webHookOverrides)
   252  
   253  	// by default, crd status should be ignored
   254  	crdOverrides := overrides[crdGK]
   255  	assert.NotNil(t, crdOverrides)
   256  	assert.Equal(t, ignoreCRDFields, crdOverrides)
   257  
   258  	// with value all, status of all objects should be ignored
   259  	_, settingsManager = fixtures(map[string]string{
   260  		"resource.compareoptions": `
   261      ignoreResourceStatusField: all`,
   262  	})
   263  	overrides, err = settingsManager.GetResourceOverrides()
   264  	assert.NoError(t, err)
   265  
   266  	globalOverrides := overrides["*/*"]
   267  	assert.NotNil(t, globalOverrides)
   268  	assert.Equal(t, ignoreStatus, globalOverrides)
   269  
   270  	// with value crd, status of crd objects should be ignored
   271  	_, settingsManager = fixtures(map[string]string{
   272  		"resource.compareoptions": `
   273      ignoreResourceStatusField: crd`,
   274  
   275  		"resource.customizations": `
   276      apiextensions.k8s.io/CustomResourceDefinition:
   277        ignoreDifferences: |
   278          jsonPointers:
   279          - /webhooks/0/clientConfig/caBundle
   280          jqPathExpressions:
   281          - .webhooks[0].clientConfig.caBundle`,
   282  	})
   283  	overrides, err = settingsManager.GetResourceOverrides()
   284  	assert.NoError(t, err)
   285  
   286  	crdOverrides = overrides[crdGK]
   287  	assert.NotNil(t, crdOverrides)
   288  	assert.Equal(t, v1alpha1.ResourceOverride{IgnoreDifferences: v1alpha1.OverrideIgnoreDiff{
   289  		JSONPointers:      []string{"/webhooks/0/clientConfig/caBundle", "/status", "/spec/preserveUnknownFields"},
   290  		JQPathExpressions: []string{".webhooks[0].clientConfig.caBundle"},
   291  	}}, crdOverrides)
   292  
   293  	// with incorrect value, status of crd objects should be ignored
   294  	_, settingsManager = fixtures(map[string]string{
   295  		"resource.compareoptions": `
   296      ignoreResourceStatusField: foobar`,
   297  	})
   298  	overrides, err = settingsManager.GetResourceOverrides()
   299  	assert.NoError(t, err)
   300  
   301  	defaultOverrides := overrides[crdGK]
   302  	assert.NotNil(t, defaultOverrides)
   303  	assert.Equal(t, ignoreStatus, defaultOverrides)
   304  	assert.Equal(t, ignoreStatus, defaultOverrides)
   305  
   306  	// with value off, status of no objects should be ignored
   307  	_, settingsManager = fixtures(map[string]string{
   308  		"resource.compareoptions": `
   309      ignoreResourceStatusField: off`,
   310  	})
   311  	overrides, err = settingsManager.GetResourceOverrides()
   312  	assert.NoError(t, err)
   313  	assert.Equal(t, 0, len(overrides))
   314  
   315  }
   316  
   317  func TestGetResourceOverridesHealthWithWildcard(t *testing.T) {
   318  	data := map[string]string{
   319  		"resource.customizations": `
   320      "*.aws.crossplane.io/*":
   321        health.lua: |
   322          foo`,
   323  	}
   324  
   325  	t.Run("TestResourceHealthOverrideWithWildcard", func(t *testing.T) {
   326  		_, settingsManager := fixtures(data)
   327  
   328  		overrides, err := settingsManager.GetResourceOverrides()
   329  		assert.NoError(t, err)
   330  		assert.Equal(t, 2, len(overrides))
   331  		assert.Equal(t, "foo", overrides["*.aws.crossplane.io/*"].HealthLua)
   332  	})
   333  }
   334  
   335  func TestSettingsManager_GetResourceOverrides_with_empty_string(t *testing.T) {
   336  	_, settingsManager := fixtures(map[string]string{
   337  		resourceCustomizationsKey: "",
   338  	})
   339  	overrides, err := settingsManager.GetResourceOverrides()
   340  	assert.NoError(t, err)
   341  
   342  	assert.Len(t, overrides, 1)
   343  }
   344  
   345  func TestGetResourceOverrides_with_splitted_keys(t *testing.T) {
   346  	data := map[string]string{
   347  		"resource.customizations": `
   348      admissionregistration.k8s.io/MutatingWebhookConfiguration:
   349        ignoreDifferences: |
   350          jsonPointers:
   351          - foo
   352        ignoreResourceUpdates: |
   353          jsonPointers:
   354          - foo
   355      certmanager.k8s.io/Certificate:
   356        health.lua.useOpenLibs: true
   357        health.lua: |
   358          foo
   359      cert-manager.io/Certificate:
   360        health.lua: |
   361          foo
   362      apps/Deployment:
   363        actions: |
   364          foo`,
   365  	}
   366  
   367  	t.Run("MergedKey", func(t *testing.T) {
   368  		crdGK := "apiextensions.k8s.io/CustomResourceDefinition"
   369  		_, settingsManager := fixtures(data)
   370  
   371  		overrides, err := settingsManager.GetResourceOverrides()
   372  		assert.NoError(t, err)
   373  		assert.Equal(t, 5, len(overrides))
   374  		assert.Equal(t, 2, len(overrides[crdGK].IgnoreDifferences.JSONPointers))
   375  		assert.Equal(t, 1, len(overrides["admissionregistration.k8s.io/MutatingWebhookConfiguration"].IgnoreDifferences.JSONPointers))
   376  		assert.Equal(t, "foo", overrides["admissionregistration.k8s.io/MutatingWebhookConfiguration"].IgnoreDifferences.JSONPointers[0])
   377  		assert.Equal(t, 1, len(overrides["admissionregistration.k8s.io/MutatingWebhookConfiguration"].IgnoreResourceUpdates.JSONPointers))
   378  		assert.Equal(t, "foo", overrides["admissionregistration.k8s.io/MutatingWebhookConfiguration"].IgnoreResourceUpdates.JSONPointers[0])
   379  		assert.Equal(t, "foo\n", overrides["certmanager.k8s.io/Certificate"].HealthLua)
   380  		assert.Equal(t, true, overrides["certmanager.k8s.io/Certificate"].UseOpenLibs)
   381  		assert.Equal(t, "foo\n", overrides["cert-manager.io/Certificate"].HealthLua)
   382  		assert.Equal(t, false, overrides["cert-manager.io/Certificate"].UseOpenLibs)
   383  		assert.Equal(t, "foo", overrides["apps/Deployment"].Actions)
   384  	})
   385  
   386  	t.Run("SplitKeys", func(t *testing.T) {
   387  		newData := map[string]string{
   388  			"resource.customizations.health.admissionregistration.k8s.io_MutatingWebhookConfiguration": "bar",
   389  			"resource.customizations.ignoreDifferences.admissionregistration.k8s.io_MutatingWebhookConfiguration": `jsonPointers:
   390          - bar`,
   391  			"resource.customizations.ignoreResourceUpdates.admissionregistration.k8s.io_MutatingWebhookConfiguration": `jsonPointers:
   392          - bar`,
   393  			"resource.customizations.knownTypeFields.admissionregistration.k8s.io_MutatingWebhookConfiguration": `
   394  - field: foo
   395    type: bar`,
   396  			"resource.customizations.health.certmanager.k8s.io_Certificate":      "bar",
   397  			"resource.customizations.health.cert-manager.io_Certificate":         "bar",
   398  			"resource.customizations.useOpenLibs.certmanager.k8s.io_Certificate": "false",
   399  			"resource.customizations.useOpenLibs.cert-manager.io_Certificate":    "true",
   400  			"resource.customizations.actions.apps_Deployment":                    "bar",
   401  			"resource.customizations.actions.Deployment":                         "bar",
   402  			"resource.customizations.health.iam-manager.k8s.io_Iamrole":          "bar",
   403  			"resource.customizations.health.Iamrole":                             "bar",
   404  			"resource.customizations.ignoreDifferences.iam-manager.k8s.io_Iamrole": `jsonPointers:
   405          - bar`,
   406  			"resource.customizations.ignoreDifferences.apps_Deployment": `jqPathExpressions:
   407          - bar`,
   408  			"resource.customizations.ignoreDifferences.all": `managedFieldsManagers:
   409          - kube-controller-manager
   410          - argo-rollouts`,
   411  			"resource.customizations.ignoreResourceUpdates.iam-manager.k8s.io_Iamrole": `jsonPointers:
   412          - bar`,
   413  			"resource.customizations.ignoreResourceUpdates.apps_Deployment": `jqPathExpressions:
   414          - bar`,
   415  		}
   416  		crdGK := "apiextensions.k8s.io/CustomResourceDefinition"
   417  
   418  		_, settingsManager := fixtures(mergemaps(data, newData))
   419  
   420  		overrides, err := settingsManager.GetResourceOverrides()
   421  		assert.NoError(t, err)
   422  		assert.Equal(t, 9, len(overrides))
   423  		assert.Equal(t, 2, len(overrides[crdGK].IgnoreDifferences.JSONPointers))
   424  		assert.Equal(t, "/status", overrides[crdGK].IgnoreDifferences.JSONPointers[0])
   425  		assert.Equal(t, "/spec/preserveUnknownFields", overrides[crdGK].IgnoreDifferences.JSONPointers[1])
   426  		assert.Equal(t, 1, len(overrides["admissionregistration.k8s.io/MutatingWebhookConfiguration"].IgnoreDifferences.JSONPointers))
   427  		assert.Equal(t, "bar", overrides["admissionregistration.k8s.io/MutatingWebhookConfiguration"].IgnoreDifferences.JSONPointers[0])
   428  		assert.Equal(t, 1, len(overrides["admissionregistration.k8s.io/MutatingWebhookConfiguration"].IgnoreResourceUpdates.JSONPointers))
   429  		assert.Equal(t, "bar", overrides["admissionregistration.k8s.io/MutatingWebhookConfiguration"].IgnoreResourceUpdates.JSONPointers[0])
   430  		assert.Equal(t, 1, len(overrides["admissionregistration.k8s.io/MutatingWebhookConfiguration"].KnownTypeFields))
   431  		assert.Equal(t, "bar", overrides["admissionregistration.k8s.io/MutatingWebhookConfiguration"].KnownTypeFields[0].Type)
   432  		assert.Equal(t, "bar", overrides["admissionregistration.k8s.io/MutatingWebhookConfiguration"].HealthLua)
   433  		assert.Equal(t, "bar", overrides["certmanager.k8s.io/Certificate"].HealthLua)
   434  		assert.Equal(t, "bar", overrides["cert-manager.io/Certificate"].HealthLua)
   435  		assert.Equal(t, false, overrides["certmanager.k8s.io/Certificate"].UseOpenLibs)
   436  		assert.Equal(t, true, overrides["cert-manager.io/Certificate"].UseOpenLibs)
   437  		assert.Equal(t, "bar", overrides["apps/Deployment"].Actions)
   438  		assert.Equal(t, "bar", overrides["Deployment"].Actions)
   439  		assert.Equal(t, "bar", overrides["iam-manager.k8s.io/Iamrole"].HealthLua)
   440  		assert.Equal(t, "bar", overrides["Iamrole"].HealthLua)
   441  		assert.Equal(t, 1, len(overrides["iam-manager.k8s.io/Iamrole"].IgnoreDifferences.JSONPointers))
   442  		assert.Equal(t, 1, len(overrides["apps/Deployment"].IgnoreDifferences.JQPathExpressions))
   443  		assert.Equal(t, "bar", overrides["apps/Deployment"].IgnoreDifferences.JQPathExpressions[0])
   444  		assert.Equal(t, 2, len(overrides["*/*"].IgnoreDifferences.ManagedFieldsManagers))
   445  		assert.Equal(t, "kube-controller-manager", overrides["*/*"].IgnoreDifferences.ManagedFieldsManagers[0])
   446  		assert.Equal(t, "argo-rollouts", overrides["*/*"].IgnoreDifferences.ManagedFieldsManagers[1])
   447  		assert.Equal(t, 1, len(overrides["iam-manager.k8s.io/Iamrole"].IgnoreResourceUpdates.JSONPointers))
   448  		assert.Equal(t, 1, len(overrides["apps/Deployment"].IgnoreResourceUpdates.JQPathExpressions))
   449  		assert.Equal(t, "bar", overrides["apps/Deployment"].IgnoreResourceUpdates.JQPathExpressions[0])
   450  	})
   451  
   452  	t.Run("SplitKeysCompareOptionsAll", func(t *testing.T) {
   453  		newData := map[string]string{
   454  			"resource.customizations.health.cert-manager.io_Certificate": "bar",
   455  			"resource.customizations.actions.apps_Deployment":            "bar",
   456  			"resource.compareoptions":                                    `ignoreResourceStatusField: all`,
   457  		}
   458  		_, settingsManager := fixtures(mergemaps(data, newData))
   459  
   460  		overrides, err := settingsManager.GetResourceOverrides()
   461  		assert.NoError(t, err)
   462  		assert.Equal(t, 5, len(overrides))
   463  		assert.Equal(t, 1, len(overrides["*/*"].IgnoreDifferences.JSONPointers))
   464  		assert.Equal(t, 1, len(overrides["admissionregistration.k8s.io/MutatingWebhookConfiguration"].IgnoreDifferences.JSONPointers))
   465  		assert.Equal(t, "foo\n", overrides["certmanager.k8s.io/Certificate"].HealthLua)
   466  		assert.Equal(t, "bar", overrides["cert-manager.io/Certificate"].HealthLua)
   467  		assert.Equal(t, "bar", overrides["apps/Deployment"].Actions)
   468  	})
   469  
   470  	t.Run("SplitKeysCompareOptionsOff", func(t *testing.T) {
   471  		newData := map[string]string{
   472  			"resource.customizations.health.cert-manager.io_Certificate": "bar",
   473  			"resource.customizations.actions.apps_Deployment":            "bar",
   474  			"resource.compareoptions":                                    `ignoreResourceStatusField: off`,
   475  		}
   476  		_, settingsManager := fixtures(mergemaps(data, newData))
   477  
   478  		overrides, err := settingsManager.GetResourceOverrides()
   479  		assert.NoError(t, err)
   480  		assert.Equal(t, 4, len(overrides))
   481  		assert.Equal(t, 1, len(overrides["admissionregistration.k8s.io/MutatingWebhookConfiguration"].IgnoreDifferences.JSONPointers))
   482  		assert.Equal(t, "foo\n", overrides["certmanager.k8s.io/Certificate"].HealthLua)
   483  		assert.Equal(t, "bar", overrides["cert-manager.io/Certificate"].HealthLua)
   484  		assert.Equal(t, "bar", overrides["apps/Deployment"].Actions)
   485  	})
   486  }
   487  
   488  func mergemaps(mapA map[string]string, mapB map[string]string) map[string]string {
   489  	for k, v := range mapA {
   490  		mapB[k] = v
   491  	}
   492  	return mapB
   493  }
   494  
   495  func TestGetIgnoreResourceUpdatesOverrides(t *testing.T) {
   496  	allDefault := v1alpha1.ResourceOverride{IgnoreDifferences: v1alpha1.OverrideIgnoreDiff{
   497  		JSONPointers: []string{"/metadata/resourceVersion", "/metadata/generation", "/metadata/managedFields"},
   498  	}}
   499  	allGK := "*/*"
   500  
   501  	testCustomizations := map[string]string{
   502  		"resource.customizations": `
   503      admissionregistration.k8s.io/MutatingWebhookConfiguration:
   504        ignoreDifferences: |
   505          jsonPointers:
   506          - /webhooks/0/clientConfig/caBundle
   507          jqPathExpressions:
   508          - .webhooks[0].clientConfig.caBundle
   509        ignoreResourceUpdates: |
   510          jsonPointers:
   511          - /webhooks/1/clientConfig/caBundle
   512          jqPathExpressions:
   513          - .webhooks[1].clientConfig.caBundle`,
   514  	}
   515  
   516  	_, settingsManager := fixtures(testCustomizations)
   517  	overrides, err := settingsManager.GetIgnoreResourceUpdatesOverrides()
   518  	assert.NoError(t, err)
   519  
   520  	// default overrides should always be present
   521  	allOverrides := overrides[allGK]
   522  	assert.NotNil(t, allOverrides)
   523  	assert.Equal(t, allDefault, allOverrides)
   524  
   525  	// without ignoreDifferencesOnResourceUpdates, only ignoreResourceUpdates should be added
   526  	assert.NotNil(t, overrides["admissionregistration.k8s.io/MutatingWebhookConfiguration"])
   527  	assert.Equal(t, v1alpha1.ResourceOverride{
   528  		IgnoreDifferences: v1alpha1.OverrideIgnoreDiff{
   529  			JSONPointers:      []string{"/webhooks/1/clientConfig/caBundle"},
   530  			JQPathExpressions: []string{".webhooks[1].clientConfig.caBundle"},
   531  		},
   532  		IgnoreResourceUpdates: v1alpha1.OverrideIgnoreDiff{},
   533  	}, overrides["admissionregistration.k8s.io/MutatingWebhookConfiguration"])
   534  
   535  	// with ignoreDifferencesOnResourceUpdates, ignoreDifferences should be added
   536  	_, settingsManager = fixtures(mergemaps(testCustomizations, map[string]string{
   537  		"resource.compareoptions": `
   538      ignoreDifferencesOnResourceUpdates: true`,
   539  	}))
   540  	overrides, err = settingsManager.GetIgnoreResourceUpdatesOverrides()
   541  	assert.NoError(t, err)
   542  
   543  	assert.NotNil(t, overrides["admissionregistration.k8s.io/MutatingWebhookConfiguration"])
   544  	assert.Equal(t, v1alpha1.ResourceOverride{
   545  		IgnoreDifferences: v1alpha1.OverrideIgnoreDiff{
   546  			JSONPointers:      []string{"/webhooks/1/clientConfig/caBundle", "/webhooks/0/clientConfig/caBundle"},
   547  			JQPathExpressions: []string{".webhooks[1].clientConfig.caBundle", ".webhooks[0].clientConfig.caBundle"},
   548  		},
   549  		IgnoreResourceUpdates: v1alpha1.OverrideIgnoreDiff{},
   550  	}, overrides["admissionregistration.k8s.io/MutatingWebhookConfiguration"])
   551  }
   552  
   553  func TestConvertToOverrideKey(t *testing.T) {
   554  	key, err := convertToOverrideKey("cert-manager.io_Certificate")
   555  	assert.NoError(t, err)
   556  	assert.Equal(t, "cert-manager.io/Certificate", key)
   557  
   558  	key, err = convertToOverrideKey("Certificate")
   559  	assert.NoError(t, err)
   560  	assert.Equal(t, "Certificate", key)
   561  
   562  	_, err = convertToOverrideKey("")
   563  	assert.NotNil(t, err)
   564  
   565  	_, err = convertToOverrideKey("_")
   566  	assert.NoError(t, err)
   567  }
   568  
   569  func TestGetResourceCompareOptions(t *testing.T) {
   570  	// ignoreAggregatedRules is true
   571  	{
   572  		_, settingsManager := fixtures(map[string]string{
   573  			"resource.compareoptions": "ignoreAggregatedRoles: true",
   574  		})
   575  		compareOptions, err := settingsManager.GetResourceCompareOptions()
   576  		assert.NoError(t, err)
   577  		assert.True(t, compareOptions.IgnoreAggregatedRoles)
   578  	}
   579  
   580  	// ignoreAggregatedRules is false
   581  	{
   582  		_, settingsManager := fixtures(map[string]string{
   583  			"resource.compareoptions": "ignoreAggregatedRoles: false",
   584  		})
   585  		compareOptions, err := settingsManager.GetResourceCompareOptions()
   586  		assert.NoError(t, err)
   587  		assert.False(t, compareOptions.IgnoreAggregatedRoles)
   588  	}
   589  
   590  	// ignoreDifferencesOnResourceUpdates is true
   591  	{
   592  		_, settingsManager := fixtures(map[string]string{
   593  			"resource.compareoptions": "ignoreDifferencesOnResourceUpdates: true",
   594  		})
   595  		compareOptions, err := settingsManager.GetResourceCompareOptions()
   596  		assert.NoError(t, err)
   597  		assert.True(t, compareOptions.IgnoreDifferencesOnResourceUpdates)
   598  	}
   599  
   600  	// ignoreDifferencesOnResourceUpdates is false
   601  	{
   602  		_, settingsManager := fixtures(map[string]string{
   603  			"resource.compareoptions": "ignoreDifferencesOnResourceUpdates: false",
   604  		})
   605  		compareOptions, err := settingsManager.GetResourceCompareOptions()
   606  		assert.NoError(t, err)
   607  		assert.False(t, compareOptions.IgnoreDifferencesOnResourceUpdates)
   608  	}
   609  
   610  	// The empty resource.compareoptions should result in default being returned
   611  	{
   612  		_, settingsManager := fixtures(map[string]string{
   613  			"resource.compareoptions": "",
   614  		})
   615  		compareOptions, err := settingsManager.GetResourceCompareOptions()
   616  		defaultOptions := GetDefaultDiffOptions()
   617  		assert.NoError(t, err)
   618  		assert.Equal(t, defaultOptions.IgnoreAggregatedRoles, compareOptions.IgnoreAggregatedRoles)
   619  		assert.Equal(t, defaultOptions.IgnoreDifferencesOnResourceUpdates, compareOptions.IgnoreDifferencesOnResourceUpdates)
   620  	}
   621  
   622  	// resource.compareoptions not defined - should result in default being returned
   623  	{
   624  		_, settingsManager := fixtures(map[string]string{})
   625  		compareOptions, err := settingsManager.GetResourceCompareOptions()
   626  		defaultOptions := GetDefaultDiffOptions()
   627  		assert.NoError(t, err)
   628  		assert.Equal(t, defaultOptions.IgnoreAggregatedRoles, compareOptions.IgnoreAggregatedRoles)
   629  		assert.Equal(t, defaultOptions.IgnoreDifferencesOnResourceUpdates, compareOptions.IgnoreDifferencesOnResourceUpdates)
   630  	}
   631  }
   632  
   633  func TestSettingsManager_GetKustomizeBuildOptions(t *testing.T) {
   634  	t.Run("Empty", func(t *testing.T) {
   635  		_, settingsManager := fixtures(map[string]string{})
   636  
   637  		settings, err := settingsManager.GetKustomizeSettings()
   638  
   639  		assert.NoError(t, err)
   640  		assert.Empty(t, settings.BuildOptions)
   641  		assert.Empty(t, settings.Versions)
   642  	})
   643  	t.Run("Set", func(t *testing.T) {
   644  		_, settingsManager := fixtures(map[string]string{
   645  			"kustomize.buildOptions":   "foo",
   646  			"kustomize.version.v3.2.1": "somePath",
   647  		})
   648  
   649  		options, err := settingsManager.GetKustomizeSettings()
   650  
   651  		assert.NoError(t, err)
   652  		assert.Equal(t, "foo", options.BuildOptions)
   653  		assert.Equal(t, []KustomizeVersion{{Name: "v3.2.1", Path: "somePath"}}, options.Versions)
   654  	})
   655  
   656  	t.Run("Kustomize settings per-version", func(t *testing.T) {
   657  		_, settingsManager := fixtures(map[string]string{
   658  			"kustomize.buildOptions":        "--global true",
   659  			"kustomize.version.v3.2.1":      "/path_3.2.1",
   660  			"kustomize.buildOptions.v3.2.3": "--options v3.2.3",
   661  			"kustomize.path.v3.2.3":         "/path_3.2.3",
   662  			"kustomize.path.v3.2.4":         "/path_3.2.4",
   663  			"kustomize.buildOptions.v3.2.4": "--options v3.2.4",
   664  			"kustomize.buildOptions.v3.2.5": "--options v3.2.5",
   665  		})
   666  
   667  		got, err := settingsManager.GetKustomizeSettings()
   668  
   669  		assert.NoError(t, err)
   670  		assert.Equal(t, "--global true", got.BuildOptions)
   671  		want := &KustomizeSettings{
   672  			BuildOptions: "--global true",
   673  			Versions: []KustomizeVersion{
   674  				{Name: "v3.2.1", Path: "/path_3.2.1"},
   675  				{Name: "v3.2.3", Path: "/path_3.2.3", BuildOptions: "--options v3.2.3"},
   676  				{Name: "v3.2.4", Path: "/path_3.2.4", BuildOptions: "--options v3.2.4"},
   677  			},
   678  		}
   679  		sortVersionsByName := func(versions []KustomizeVersion) {
   680  			sort.Slice(versions, func(i, j int) bool {
   681  				return versions[i].Name > versions[j].Name
   682  			})
   683  		}
   684  		sortVersionsByName(want.Versions)
   685  		sortVersionsByName(got.Versions)
   686  		assert.EqualValues(t, want, got)
   687  	})
   688  
   689  	t.Run("Kustomize settings per-version with duplicate versions", func(t *testing.T) {
   690  		_, settingsManager := fixtures(map[string]string{
   691  			"kustomize.buildOptions":        "--global true",
   692  			"kustomize.version.v3.2.1":      "/path_3.2.1",
   693  			"kustomize.buildOptions.v3.2.1": "--options v3.2.3",
   694  			"kustomize.path.v3.2.2":         "/other_path_3.2.2",
   695  			"kustomize.path.v3.2.1":         "/other_path_3.2.1",
   696  		})
   697  
   698  		got, err := settingsManager.GetKustomizeSettings()
   699  		assert.ErrorContains(t, err, "found duplicate kustomize version: v3.2.1")
   700  		assert.Empty(t, got)
   701  	})
   702  
   703  	t.Run("Config map with no Kustomize settings", func(t *testing.T) {
   704  		_, settingsManager := fixtures(map[string]string{
   705  			"other.options": "--global true",
   706  		})
   707  
   708  		got, err := settingsManager.GetKustomizeSettings()
   709  		assert.NoError(t, err)
   710  		assert.Empty(t, got)
   711  	})
   712  }
   713  
   714  func TestKustomizeSettings_GetOptions(t *testing.T) {
   715  	settings := KustomizeSettings{
   716  		BuildOptions: "--opt1 val1",
   717  		Versions: []KustomizeVersion{
   718  			{Name: "v1", Path: "path_v1"},
   719  			{Name: "v2", Path: "path_v2"},
   720  			{Name: "v3", Path: "path_v3", BuildOptions: "--opt2 val2"},
   721  		},
   722  	}
   723  
   724  	t.Run("VersionDoesNotExist", func(t *testing.T) {
   725  		_, err := settings.GetOptions(v1alpha1.ApplicationSource{
   726  			Kustomize: &v1alpha1.ApplicationSourceKustomize{Version: "v4"}})
   727  		assert.Error(t, err)
   728  	})
   729  
   730  	t.Run("DefaultBuildOptions", func(t *testing.T) {
   731  		ver, err := settings.GetOptions(v1alpha1.ApplicationSource{})
   732  		if !assert.NoError(t, err) {
   733  			return
   734  		}
   735  		assert.Equal(t, "", ver.BinaryPath)
   736  		assert.Equal(t, "--opt1 val1", ver.BuildOptions)
   737  	})
   738  
   739  	t.Run("VersionExists", func(t *testing.T) {
   740  		ver, err := settings.GetOptions(v1alpha1.ApplicationSource{
   741  			Kustomize: &v1alpha1.ApplicationSourceKustomize{Version: "v2"}})
   742  		if !assert.NoError(t, err) {
   743  			return
   744  		}
   745  		assert.Equal(t, "path_v2", ver.BinaryPath)
   746  		assert.Equal(t, "", ver.BuildOptions)
   747  	})
   748  
   749  	t.Run("VersionExistsWithBuildOption", func(t *testing.T) {
   750  		ver, err := settings.GetOptions(v1alpha1.ApplicationSource{
   751  			Kustomize: &v1alpha1.ApplicationSourceKustomize{Version: "v3"}})
   752  		if !assert.NoError(t, err) {
   753  			return
   754  		}
   755  		assert.Equal(t, "path_v3", ver.BinaryPath)
   756  		assert.Equal(t, "--opt2 val2", ver.BuildOptions)
   757  	})
   758  }
   759  
   760  func TestGetGoogleAnalytics(t *testing.T) {
   761  	_, settingsManager := fixtures(map[string]string{
   762  		"ga.trackingid": "123",
   763  	})
   764  	ga, err := settingsManager.GetGoogleAnalytics()
   765  	assert.NoError(t, err)
   766  	assert.Equal(t, "123", ga.TrackingID)
   767  	assert.Equal(t, true, ga.AnonymizeUsers)
   768  }
   769  
   770  func TestSettingsManager_GetHelp(t *testing.T) {
   771  	t.Run("Default", func(t *testing.T) {
   772  		_, settingsManager := fixtures(nil)
   773  		h, err := settingsManager.GetHelp()
   774  		assert.NoError(t, err)
   775  		assert.Empty(t, h.ChatURL)
   776  		assert.Empty(t, h.ChatText)
   777  
   778  	})
   779  	t.Run("Set", func(t *testing.T) {
   780  		_, settingsManager := fixtures(map[string]string{
   781  			"help.chatUrl":  "foo",
   782  			"help.chatText": "bar",
   783  		})
   784  		h, err := settingsManager.GetHelp()
   785  		assert.NoError(t, err)
   786  		assert.Equal(t, "foo", h.ChatURL)
   787  		assert.Equal(t, "bar", h.ChatText)
   788  	})
   789  	t.Run("SetOnlyChatUrl", func(t *testing.T) {
   790  		_, settingManager := fixtures(map[string]string{
   791  			"help.chatUrl": "foo",
   792  		})
   793  		h, err := settingManager.GetHelp()
   794  		assert.NoError(t, err)
   795  		assert.Equal(t, "foo", h.ChatURL)
   796  		assert.Equal(t, "Chat now!", h.ChatText)
   797  	})
   798  	t.Run("SetOnlyChatText", func(t *testing.T) {
   799  		_, settingManager := fixtures(map[string]string{
   800  			"help.chatText": "bar",
   801  		})
   802  		h, err := settingManager.GetHelp()
   803  		assert.NoError(t, err)
   804  		assert.Empty(t, h.ChatURL)
   805  		assert.Empty(t, h.ChatText)
   806  	})
   807  	t.Run("GetBinaryUrls", func(t *testing.T) {
   808  		_, settingsManager := fixtures(map[string]string{
   809  			"help.download.darwin-amd64": "amd64-path",
   810  			"help.download.linux-s390x":  "s390x-path",
   811  			"help.download.unsupported":  "nowhere",
   812  		})
   813  		h, err := settingsManager.GetHelp()
   814  		assert.NoError(t, err)
   815  		assert.Equal(t, map[string]string{"darwin-amd64": "amd64-path", "linux-s390x": "s390x-path"}, h.BinaryURLs)
   816  	})
   817  }
   818  
   819  func TestSettingsManager_GetSettings(t *testing.T) {
   820  	t.Run("UserSessionDurationNotProvided", func(t *testing.T) {
   821  		kubeClient := fake.NewSimpleClientset(
   822  			&v1.ConfigMap{
   823  				ObjectMeta: metav1.ObjectMeta{
   824  					Name:      common.ArgoCDConfigMapName,
   825  					Namespace: "default",
   826  					Labels: map[string]string{
   827  						"app.kubernetes.io/part-of": "argocd",
   828  					},
   829  				},
   830  				Data: nil,
   831  			},
   832  			&v1.Secret{
   833  				ObjectMeta: metav1.ObjectMeta{
   834  					Name:      common.ArgoCDSecretName,
   835  					Namespace: "default",
   836  					Labels: map[string]string{
   837  						"app.kubernetes.io/part-of": "argocd",
   838  					},
   839  				},
   840  				Data: map[string][]byte{
   841  					"server.secretkey": nil,
   842  				},
   843  			},
   844  		)
   845  		settingsManager := NewSettingsManager(context.Background(), kubeClient, "default")
   846  		s, err := settingsManager.GetSettings()
   847  		assert.NoError(t, err)
   848  		assert.Equal(t, time.Hour*24, s.UserSessionDuration)
   849  	})
   850  	t.Run("UserSessionDurationInvalidFormat", func(t *testing.T) {
   851  		kubeClient := fake.NewSimpleClientset(
   852  			&v1.ConfigMap{
   853  				ObjectMeta: metav1.ObjectMeta{
   854  					Name:      common.ArgoCDConfigMapName,
   855  					Namespace: "default",
   856  					Labels: map[string]string{
   857  						"app.kubernetes.io/part-of": "argocd",
   858  					},
   859  				},
   860  				Data: map[string]string{
   861  					"users.session.duration": "10hh",
   862  				},
   863  			},
   864  			&v1.Secret{
   865  				ObjectMeta: metav1.ObjectMeta{
   866  					Name:      common.ArgoCDSecretName,
   867  					Namespace: "default",
   868  					Labels: map[string]string{
   869  						"app.kubernetes.io/part-of": "argocd",
   870  					},
   871  				},
   872  				Data: map[string][]byte{
   873  					"server.secretkey": nil,
   874  				},
   875  			},
   876  		)
   877  		settingsManager := NewSettingsManager(context.Background(), kubeClient, "default")
   878  		s, err := settingsManager.GetSettings()
   879  		assert.NoError(t, err)
   880  		assert.Equal(t, time.Hour*24, s.UserSessionDuration)
   881  	})
   882  	t.Run("UserSessionDurationProvided", func(t *testing.T) {
   883  		kubeClient := fake.NewSimpleClientset(
   884  			&v1.ConfigMap{
   885  				ObjectMeta: metav1.ObjectMeta{
   886  					Name:      common.ArgoCDConfigMapName,
   887  					Namespace: "default",
   888  					Labels: map[string]string{
   889  						"app.kubernetes.io/part-of": "argocd",
   890  					},
   891  				},
   892  				Data: map[string]string{
   893  					"users.session.duration": "10h",
   894  				},
   895  			},
   896  			&v1.Secret{
   897  				ObjectMeta: metav1.ObjectMeta{
   898  					Name:      common.ArgoCDSecretName,
   899  					Namespace: "default",
   900  					Labels: map[string]string{
   901  						"app.kubernetes.io/part-of": "argocd",
   902  					},
   903  				},
   904  				Data: map[string][]byte{
   905  					"server.secretkey": nil,
   906  				},
   907  			},
   908  		)
   909  		settingsManager := NewSettingsManager(context.Background(), kubeClient, "default")
   910  		s, err := settingsManager.GetSettings()
   911  		assert.NoError(t, err)
   912  		assert.Equal(t, time.Hour*10, s.UserSessionDuration)
   913  	})
   914  }
   915  
   916  func TestGetOIDCConfig(t *testing.T) {
   917  	kubeClient := fake.NewSimpleClientset(
   918  		&v1.ConfigMap{
   919  			ObjectMeta: metav1.ObjectMeta{
   920  				Name:      common.ArgoCDConfigMapName,
   921  				Namespace: "default",
   922  				Labels: map[string]string{
   923  					"app.kubernetes.io/part-of": "argocd",
   924  				},
   925  			},
   926  			Data: map[string]string{
   927  				"oidc.config": "\n  requestedIDTokenClaims: {\"groups\": {\"essential\": true}}\n",
   928  			},
   929  		},
   930  		&v1.Secret{
   931  			ObjectMeta: metav1.ObjectMeta{
   932  				Name:      common.ArgoCDSecretName,
   933  				Namespace: "default",
   934  				Labels: map[string]string{
   935  					"app.kubernetes.io/part-of": "argocd",
   936  				},
   937  			},
   938  			Data: map[string][]byte{
   939  				"admin.password":   nil,
   940  				"server.secretkey": nil,
   941  			},
   942  		},
   943  	)
   944  	settingsManager := NewSettingsManager(context.Background(), kubeClient, "default")
   945  	settings, err := settingsManager.GetSettings()
   946  	assert.NoError(t, err)
   947  
   948  	oidcConfig := settings.OIDCConfig()
   949  	assert.NotNil(t, oidcConfig)
   950  
   951  	claim := oidcConfig.RequestedIDTokenClaims["groups"]
   952  	assert.NotNil(t, claim)
   953  	assert.Equal(t, true, claim.Essential)
   954  }
   955  
   956  func TestRedirectURL(t *testing.T) {
   957  	cases := map[string][]string{
   958  		"https://localhost:4000":         {"https://localhost:4000/auth/callback", "https://localhost:4000/api/dex/callback"},
   959  		"https://localhost:4000/":        {"https://localhost:4000/auth/callback", "https://localhost:4000/api/dex/callback"},
   960  		"https://localhost:4000/argocd":  {"https://localhost:4000/argocd/auth/callback", "https://localhost:4000/argocd/api/dex/callback"},
   961  		"https://localhost:4000/argocd/": {"https://localhost:4000/argocd/auth/callback", "https://localhost:4000/argocd/api/dex/callback"},
   962  	}
   963  	for given, expected := range cases {
   964  		settings := ArgoCDSettings{URL: given}
   965  		redirectURL, err := settings.RedirectURL()
   966  		assert.NoError(t, err)
   967  		assert.Equal(t, expected[0], redirectURL)
   968  		dexRedirectURL, err := settings.DexRedirectURL()
   969  		assert.NoError(t, err)
   970  		assert.Equal(t, expected[1], dexRedirectURL)
   971  	}
   972  }
   973  
   974  func Test_validateExternalURL(t *testing.T) {
   975  	tests := []struct {
   976  		name   string
   977  		url    string
   978  		errMsg string
   979  	}{
   980  		{name: "Valid URL", url: "https://my.domain.com"},
   981  		{name: "No URL - Valid", url: ""},
   982  		{name: "Invalid URL", url: "my.domain.com", errMsg: "URL must include http or https protocol"},
   983  	}
   984  	for _, tt := range tests {
   985  		t.Run(tt.name, func(t *testing.T) {
   986  			err := validateExternalURL(tt.url)
   987  			if tt.errMsg != "" {
   988  				assert.EqualError(t, err, tt.errMsg)
   989  			} else {
   990  				assert.NoError(t, err)
   991  			}
   992  		})
   993  	}
   994  }
   995  
   996  func TestGetOIDCSecretTrim(t *testing.T) {
   997  	kubeClient := fake.NewSimpleClientset(
   998  		&v1.ConfigMap{
   999  			ObjectMeta: metav1.ObjectMeta{
  1000  				Name:      common.ArgoCDConfigMapName,
  1001  				Namespace: "default",
  1002  				Labels: map[string]string{
  1003  					"app.kubernetes.io/part-of": "argocd",
  1004  				},
  1005  			},
  1006  			Data: map[string]string{
  1007  				"oidc.config": "\n  name: Okta\n  clientSecret: test-secret\r\n \n  clientID: aaaabbbbccccddddeee\n",
  1008  			},
  1009  		},
  1010  		&v1.Secret{
  1011  			ObjectMeta: metav1.ObjectMeta{
  1012  				Name:      common.ArgoCDSecretName,
  1013  				Namespace: "default",
  1014  				Labels: map[string]string{
  1015  					"app.kubernetes.io/part-of": "argocd",
  1016  				},
  1017  			},
  1018  			Data: map[string][]byte{
  1019  				"admin.password":   nil,
  1020  				"server.secretkey": nil,
  1021  			},
  1022  		},
  1023  	)
  1024  	settingsManager := NewSettingsManager(context.Background(), kubeClient, "default")
  1025  	settings, err := settingsManager.GetSettings()
  1026  	assert.NoError(t, err)
  1027  
  1028  	oidcConfig := settings.OIDCConfig()
  1029  	assert.NotNil(t, oidcConfig)
  1030  	assert.Equal(t, "test-secret", oidcConfig.ClientSecret)
  1031  }
  1032  
  1033  func getCNFromCertificate(cert *tls.Certificate) string {
  1034  	c, err := x509.ParseCertificate(cert.Certificate[0])
  1035  	if err != nil {
  1036  		return ""
  1037  	}
  1038  	return c.Subject.CommonName
  1039  }
  1040  
  1041  func Test_GetTLSConfiguration(t *testing.T) {
  1042  	t.Run("Valid external TLS secret with success", func(t *testing.T) {
  1043  		kubeClient := fake.NewSimpleClientset(
  1044  			&v1.ConfigMap{
  1045  				ObjectMeta: metav1.ObjectMeta{
  1046  					Name:      common.ArgoCDConfigMapName,
  1047  					Namespace: "default",
  1048  					Labels: map[string]string{
  1049  						"app.kubernetes.io/part-of": "argocd",
  1050  					},
  1051  				},
  1052  				Data: map[string]string{
  1053  					"oidc.config": "\n  name: Okta\n  clientSecret: test-secret\r\n \n  clientID: aaaabbbbccccddddeee\n",
  1054  				},
  1055  			},
  1056  			&v1.Secret{
  1057  				ObjectMeta: metav1.ObjectMeta{
  1058  					Name:      common.ArgoCDSecretName,
  1059  					Namespace: "default",
  1060  					Labels: map[string]string{
  1061  						"app.kubernetes.io/part-of": "argocd",
  1062  					},
  1063  				},
  1064  				Data: map[string][]byte{
  1065  					"admin.password":   nil,
  1066  					"server.secretkey": nil,
  1067  				},
  1068  			},
  1069  			&v1.Secret{
  1070  				ObjectMeta: metav1.ObjectMeta{
  1071  					Name:      externalServerTLSSecretName,
  1072  					Namespace: "default",
  1073  				},
  1074  				Data: map[string][]byte{
  1075  					"tls.crt": []byte(testutil.MustLoadFileToString("../../test/fixture/certs/argocd-test-server.crt")),
  1076  					"tls.key": []byte(testutil.MustLoadFileToString("../../test/fixture/certs/argocd-test-server.key")),
  1077  				},
  1078  			},
  1079  		)
  1080  		settingsManager := NewSettingsManager(context.Background(), kubeClient, "default")
  1081  		settings, err := settingsManager.GetSettings()
  1082  		assert.NoError(t, err)
  1083  		assert.True(t, settings.CertificateIsExternal)
  1084  		assert.NotNil(t, settings.Certificate)
  1085  		assert.Contains(t, getCNFromCertificate(settings.Certificate), "localhost")
  1086  	})
  1087  
  1088  	t.Run("Valid external TLS secret overrides argocd-secret", func(t *testing.T) {
  1089  		kubeClient := fake.NewSimpleClientset(
  1090  			&v1.ConfigMap{
  1091  				ObjectMeta: metav1.ObjectMeta{
  1092  					Name:      common.ArgoCDConfigMapName,
  1093  					Namespace: "default",
  1094  					Labels: map[string]string{
  1095  						"app.kubernetes.io/part-of": "argocd",
  1096  					},
  1097  				},
  1098  				Data: map[string]string{
  1099  					"oidc.config": "\n  name: Okta\n  clientSecret: test-secret\r\n \n  clientID: aaaabbbbccccddddeee\n",
  1100  				},
  1101  			},
  1102  			&v1.Secret{
  1103  				ObjectMeta: metav1.ObjectMeta{
  1104  					Name:      common.ArgoCDSecretName,
  1105  					Namespace: "default",
  1106  					Labels: map[string]string{
  1107  						"app.kubernetes.io/part-of": "argocd",
  1108  					},
  1109  				},
  1110  				Data: map[string][]byte{
  1111  					"admin.password":   nil,
  1112  					"server.secretkey": nil,
  1113  					"tls.crt":          []byte(testutil.MustLoadFileToString("../../test/fixture/certs/argocd-e2e-server.crt")),
  1114  					"tls.key":          []byte(testutil.MustLoadFileToString("../../test/fixture/certs/argocd-e2e-server.key")),
  1115  				},
  1116  			},
  1117  			&v1.Secret{
  1118  				ObjectMeta: metav1.ObjectMeta{
  1119  					Name:      externalServerTLSSecretName,
  1120  					Namespace: "default",
  1121  				},
  1122  				Data: map[string][]byte{
  1123  					"tls.crt": []byte(testutil.MustLoadFileToString("../../test/fixture/certs/argocd-test-server.crt")),
  1124  					"tls.key": []byte(testutil.MustLoadFileToString("../../test/fixture/certs/argocd-test-server.key")),
  1125  				},
  1126  			},
  1127  		)
  1128  		settingsManager := NewSettingsManager(context.Background(), kubeClient, "default")
  1129  		settings, err := settingsManager.GetSettings()
  1130  		assert.NoError(t, err)
  1131  		assert.True(t, settings.CertificateIsExternal)
  1132  		assert.NotNil(t, settings.Certificate)
  1133  		assert.Contains(t, getCNFromCertificate(settings.Certificate), "localhost")
  1134  	})
  1135  	t.Run("Invalid external TLS secret", func(t *testing.T) {
  1136  		kubeClient := fake.NewSimpleClientset(
  1137  			&v1.ConfigMap{
  1138  				ObjectMeta: metav1.ObjectMeta{
  1139  					Name:      common.ArgoCDConfigMapName,
  1140  					Namespace: "default",
  1141  					Labels: map[string]string{
  1142  						"app.kubernetes.io/part-of": "argocd",
  1143  					},
  1144  				},
  1145  				Data: map[string]string{
  1146  					"oidc.config": "\n  name: Okta\n  clientSecret: test-secret\r\n \n  clientID: aaaabbbbccccddddeee\n",
  1147  				},
  1148  			},
  1149  			&v1.Secret{
  1150  				ObjectMeta: metav1.ObjectMeta{
  1151  					Name:      common.ArgoCDSecretName,
  1152  					Namespace: "default",
  1153  					Labels: map[string]string{
  1154  						"app.kubernetes.io/part-of": "argocd",
  1155  					},
  1156  				},
  1157  				Data: map[string][]byte{
  1158  					"admin.password":   nil,
  1159  					"server.secretkey": nil,
  1160  				},
  1161  			},
  1162  			&v1.Secret{
  1163  				ObjectMeta: metav1.ObjectMeta{
  1164  					Name:      externalServerTLSSecretName,
  1165  					Namespace: "default",
  1166  				},
  1167  				Data: map[string][]byte{
  1168  					"tls.crt": []byte(""),
  1169  					"tls.key": []byte(""),
  1170  				},
  1171  			},
  1172  		)
  1173  		settingsManager := NewSettingsManager(context.Background(), kubeClient, "default")
  1174  		settings, err := settingsManager.GetSettings()
  1175  		assert.Error(t, err)
  1176  		assert.Contains(t, err.Error(), "could not read from secret")
  1177  		assert.NotNil(t, settings)
  1178  	})
  1179  	t.Run("No external TLS secret", func(t *testing.T) {
  1180  		kubeClient := fake.NewSimpleClientset(
  1181  			&v1.ConfigMap{
  1182  				ObjectMeta: metav1.ObjectMeta{
  1183  					Name:      common.ArgoCDConfigMapName,
  1184  					Namespace: "default",
  1185  					Labels: map[string]string{
  1186  						"app.kubernetes.io/part-of": "argocd",
  1187  					},
  1188  				},
  1189  				Data: map[string]string{
  1190  					"oidc.config": "\n  name: Okta\n  clientSecret: test-secret\r\n \n  clientID: aaaabbbbccccddddeee\n",
  1191  				},
  1192  			},
  1193  			&v1.Secret{
  1194  				ObjectMeta: metav1.ObjectMeta{
  1195  					Name:      common.ArgoCDSecretName,
  1196  					Namespace: "default",
  1197  					Labels: map[string]string{
  1198  						"app.kubernetes.io/part-of": "argocd",
  1199  					},
  1200  				},
  1201  				Data: map[string][]byte{
  1202  					"admin.password":   nil,
  1203  					"server.secretkey": nil,
  1204  					"tls.crt":          []byte(testutil.MustLoadFileToString("../../test/fixture/certs/argocd-e2e-server.crt")),
  1205  					"tls.key":          []byte(testutil.MustLoadFileToString("../../test/fixture/certs/argocd-e2e-server.key")),
  1206  				},
  1207  			},
  1208  		)
  1209  		settingsManager := NewSettingsManager(context.Background(), kubeClient, "default")
  1210  		settings, err := settingsManager.GetSettings()
  1211  		assert.NoError(t, err)
  1212  		assert.False(t, settings.CertificateIsExternal)
  1213  		assert.NotNil(t, settings.Certificate)
  1214  		assert.Contains(t, getCNFromCertificate(settings.Certificate), "Argo CD E2E")
  1215  	})
  1216  }
  1217  
  1218  func TestDownloadArgoCDBinaryUrls(t *testing.T) {
  1219  	_, settingsManager := fixtures(map[string]string{
  1220  		"help.download.darwin-amd64": "some-url",
  1221  	})
  1222  	argoCDCM, err := settingsManager.getConfigMap()
  1223  	assert.NoError(t, err)
  1224  	assert.Equal(t, "some-url", argoCDCM.Data["help.download.darwin-amd64"])
  1225  
  1226  	_, settingsManager = fixtures(map[string]string{
  1227  		"help.download.linux-s390x": "some-url",
  1228  	})
  1229  	argoCDCM, err = settingsManager.getConfigMap()
  1230  	assert.NoError(t, err)
  1231  	assert.Equal(t, "some-url", argoCDCM.Data["help.download.linux-s390x"])
  1232  
  1233  	_, settingsManager = fixtures(map[string]string{
  1234  		"help.download.unsupported": "some-url",
  1235  	})
  1236  	argoCDCM, err = settingsManager.getConfigMap()
  1237  	assert.NoError(t, err)
  1238  	assert.Equal(t, "some-url", argoCDCM.Data["help.download.unsupported"])
  1239  }
  1240  
  1241  func TestSecretKeyRef(t *testing.T) {
  1242  	data := map[string]string{
  1243  		"oidc.config": `name: Okta
  1244  issuer: $acme:issuerSecret
  1245  clientID: aaaabbbbccccddddeee
  1246  clientSecret: $acme:clientSecret
  1247  # Optional set of OIDC scopes to request. If omitted, defaults to: ["openid", "profile", "email", "groups"]
  1248  requestedScopes: ["openid", "profile", "email"]
  1249  # Optional set of OIDC claims to request on the ID token.
  1250  requestedIDTokenClaims: {"groups": {"essential": true}}`,
  1251  	}
  1252  	cm := &v1.ConfigMap{
  1253  		ObjectMeta: metav1.ObjectMeta{
  1254  			Name:      common.ArgoCDConfigMapName,
  1255  			Namespace: "default",
  1256  			Labels: map[string]string{
  1257  				"app.kubernetes.io/part-of": "argocd",
  1258  			},
  1259  		},
  1260  		Data: data,
  1261  	}
  1262  	argocdSecret := &v1.Secret{
  1263  		ObjectMeta: metav1.ObjectMeta{
  1264  			Name:      common.ArgoCDSecretName,
  1265  			Namespace: "default",
  1266  		},
  1267  		Data: map[string][]byte{
  1268  			"admin.password":   nil,
  1269  			"server.secretkey": nil,
  1270  		},
  1271  	}
  1272  	secret := &v1.Secret{
  1273  		ObjectMeta: metav1.ObjectMeta{
  1274  			Name:      "acme",
  1275  			Namespace: "default",
  1276  			Labels: map[string]string{
  1277  				"app.kubernetes.io/part-of": "argocd",
  1278  			},
  1279  		},
  1280  		Data: map[string][]byte{
  1281  			"issuerSecret": []byte("https://dev-123456.oktapreview.com"),
  1282  			"clientSecret": []byte("deadbeef"),
  1283  		},
  1284  	}
  1285  	kubeClient := fake.NewSimpleClientset(cm, secret, argocdSecret)
  1286  	settingsManager := NewSettingsManager(context.Background(), kubeClient, "default")
  1287  
  1288  	settings, err := settingsManager.GetSettings()
  1289  	assert.NoError(t, err)
  1290  
  1291  	oidcConfig := settings.OIDCConfig()
  1292  	assert.Equal(t, oidcConfig.Issuer, "https://dev-123456.oktapreview.com")
  1293  	assert.Equal(t, oidcConfig.ClientSecret, "deadbeef")
  1294  }
  1295  
  1296  func TestGetEnableManifestGeneration(t *testing.T) {
  1297  	testCases := []struct {
  1298  		name    string
  1299  		enabled bool
  1300  		data    map[string]string
  1301  		source  string
  1302  	}{{
  1303  		name:    "default",
  1304  		enabled: true,
  1305  		data:    map[string]string{},
  1306  		source:  string(v1alpha1.ApplicationSourceTypeKustomize),
  1307  	}, {
  1308  		name:    "disabled",
  1309  		enabled: false,
  1310  		data:    map[string]string{"kustomize.enable": `false`},
  1311  		source:  string(v1alpha1.ApplicationSourceTypeKustomize),
  1312  	}, {
  1313  		name:    "enabled",
  1314  		enabled: true,
  1315  		data:    map[string]string{"kustomize.enable": `true`},
  1316  		source:  string(v1alpha1.ApplicationSourceTypeKustomize),
  1317  	}}
  1318  	for i := range testCases {
  1319  		tc := testCases[i]
  1320  		t.Run(tc.name, func(t *testing.T) {
  1321  			cm := &v1.ConfigMap{
  1322  				ObjectMeta: metav1.ObjectMeta{
  1323  					Name:      common.ArgoCDConfigMapName,
  1324  					Namespace: "default",
  1325  					Labels: map[string]string{
  1326  						"app.kubernetes.io/part-of": "argocd",
  1327  					},
  1328  				},
  1329  				Data: tc.data,
  1330  			}
  1331  			argocdSecret := &v1.Secret{
  1332  				ObjectMeta: metav1.ObjectMeta{
  1333  					Name:      common.ArgoCDSecretName,
  1334  					Namespace: "default",
  1335  				},
  1336  				Data: map[string][]byte{
  1337  					"admin.password":   nil,
  1338  					"server.secretkey": nil,
  1339  				},
  1340  			}
  1341  
  1342  			kubeClient := fake.NewSimpleClientset(cm, argocdSecret)
  1343  			settingsManager := NewSettingsManager(context.Background(), kubeClient, "default")
  1344  
  1345  			enableManifestGeneration, err := settingsManager.GetEnabledSourceTypes()
  1346  			require.NoError(t, err)
  1347  
  1348  			assert.Equal(t, enableManifestGeneration[tc.source], tc.enabled)
  1349  		})
  1350  	}
  1351  }
  1352  
  1353  func TestGetHelmSettings(t *testing.T) {
  1354  	testCases := []struct {
  1355  		name     string
  1356  		data     map[string]string
  1357  		expected []string
  1358  	}{{
  1359  		name:     "Default",
  1360  		data:     map[string]string{},
  1361  		expected: []string{"http", "https"},
  1362  	}, {
  1363  		name: "Configured Not Empty",
  1364  		data: map[string]string{
  1365  			"helm.valuesFileSchemes": "s3, git",
  1366  		},
  1367  		expected: []string{"s3", "git"},
  1368  	}, {
  1369  		name: "Configured Empty",
  1370  		data: map[string]string{
  1371  			"helm.valuesFileSchemes": "",
  1372  		},
  1373  		expected: nil,
  1374  	}}
  1375  
  1376  	for i := range testCases {
  1377  		tc := testCases[i]
  1378  		t.Run(tc.name, func(t *testing.T) {
  1379  			cm := &v1.ConfigMap{
  1380  				ObjectMeta: metav1.ObjectMeta{
  1381  					Name:      common.ArgoCDConfigMapName,
  1382  					Namespace: "default",
  1383  					Labels: map[string]string{
  1384  						"app.kubernetes.io/part-of": "argocd",
  1385  					},
  1386  				},
  1387  				Data: tc.data,
  1388  			}
  1389  			argocdSecret := &v1.Secret{
  1390  				ObjectMeta: metav1.ObjectMeta{
  1391  					Name:      common.ArgoCDSecretName,
  1392  					Namespace: "default",
  1393  				},
  1394  				Data: map[string][]byte{
  1395  					"admin.password":   nil,
  1396  					"server.secretkey": nil,
  1397  				},
  1398  			}
  1399  			secret := &v1.Secret{
  1400  				ObjectMeta: metav1.ObjectMeta{
  1401  					Name:      "acme",
  1402  					Namespace: "default",
  1403  					Labels: map[string]string{
  1404  						"app.kubernetes.io/part-of": "argocd",
  1405  					},
  1406  				},
  1407  				Data: map[string][]byte{
  1408  					"clientSecret": []byte("deadbeef"),
  1409  				},
  1410  			}
  1411  			kubeClient := fake.NewSimpleClientset(cm, secret, argocdSecret)
  1412  			settingsManager := NewSettingsManager(context.Background(), kubeClient, "default")
  1413  
  1414  			helmSettings, err := settingsManager.GetHelmSettings()
  1415  			assert.NoError(t, err)
  1416  
  1417  			assert.ElementsMatch(t, tc.expected, helmSettings.ValuesFileSchemes)
  1418  		})
  1419  	}
  1420  }
  1421  func TestArgoCDSettings_OIDCTLSConfig_OIDCTLSInsecureSkipVerify(t *testing.T) {
  1422  	certParsed, err := tls.X509KeyPair(test.Cert, test.PrivateKey)
  1423  	require.NoError(t, err)
  1424  
  1425  	testCases := []struct {
  1426  		name               string
  1427  		settings           *ArgoCDSettings
  1428  		expectNilTLSConfig bool
  1429  	}{
  1430  		{
  1431  			name: "OIDC configured, no root CA",
  1432  			settings: &ArgoCDSettings{OIDCConfigRAW: `name: Test
  1433  issuer: aaa
  1434  clientID: xxx
  1435  clientSecret: yyy
  1436  requestedScopes: ["oidc"]`},
  1437  		},
  1438  		{
  1439  			name: "OIDC configured, valid root CA",
  1440  			settings: &ArgoCDSettings{OIDCConfigRAW: fmt.Sprintf(`
  1441  name: Test
  1442  issuer: aaa
  1443  clientID: xxx
  1444  clientSecret: yyy
  1445  requestedScopes: ["oidc"]
  1446  rootCA: |
  1447    %s
  1448  `, strings.Replace(string(test.Cert), "\n", "\n  ", -1))},
  1449  		},
  1450  		{
  1451  			name: "OIDC configured, invalid root CA",
  1452  			settings: &ArgoCDSettings{OIDCConfigRAW: `name: Test
  1453  issuer: aaa
  1454  clientID: xxx
  1455  clientSecret: yyy
  1456  requestedScopes: ["oidc"]
  1457  rootCA: "invalid"`},
  1458  		},
  1459  		{
  1460  			name:               "OIDC not configured, no cert configured",
  1461  			settings:           &ArgoCDSettings{},
  1462  			expectNilTLSConfig: true,
  1463  		},
  1464  		{
  1465  			name:     "OIDC not configured, cert configured",
  1466  			settings: &ArgoCDSettings{Certificate: &certParsed},
  1467  		},
  1468  	}
  1469  
  1470  	for _, testCase := range testCases {
  1471  		testCase := testCase
  1472  
  1473  		t.Run(testCase.name, func(t *testing.T) {
  1474  			if testCase.expectNilTLSConfig {
  1475  				assert.Nil(t, testCase.settings.OIDCTLSConfig())
  1476  			} else {
  1477  				assert.False(t, testCase.settings.OIDCTLSConfig().InsecureSkipVerify)
  1478  
  1479  				testCase.settings.OIDCTLSInsecureSkipVerify = true
  1480  
  1481  				assert.True(t, testCase.settings.OIDCTLSConfig().InsecureSkipVerify)
  1482  			}
  1483  		})
  1484  	}
  1485  }
  1486  
  1487  func Test_OAuth2AllowedAudiences(t *testing.T) {
  1488  	testCases := []struct {
  1489  		name     string
  1490  		settings *ArgoCDSettings
  1491  		expected []string
  1492  	}{
  1493  		{
  1494  			name:     "Empty",
  1495  			settings: &ArgoCDSettings{},
  1496  			expected: []string{},
  1497  		},
  1498  		{
  1499  			name: "OIDC configured, no audiences specified, clientID used",
  1500  			settings: &ArgoCDSettings{OIDCConfigRAW: `name: Test
  1501  issuer: aaa
  1502  clientID: xxx
  1503  clientSecret: yyy
  1504  requestedScopes: ["oidc"]`},
  1505  			expected: []string{"xxx"},
  1506  		},
  1507  		{
  1508  			name: "OIDC configured, no audiences specified, clientID and cliClientID used",
  1509  			settings: &ArgoCDSettings{OIDCConfigRAW: `name: Test
  1510  issuer: aaa
  1511  clientID: xxx
  1512  cliClientID: cli-xxx
  1513  clientSecret: yyy
  1514  requestedScopes: ["oidc"]`},
  1515  			expected: []string{"xxx", "cli-xxx"},
  1516  		},
  1517  		{
  1518  			name: "OIDC configured, audiences specified",
  1519  			settings: &ArgoCDSettings{OIDCConfigRAW: `name: Test
  1520  issuer: aaa
  1521  clientID: xxx
  1522  clientSecret: yyy
  1523  requestedScopes: ["oidc"]
  1524  allowedAudiences: ["aud1", "aud2"]`},
  1525  			expected: []string{"aud1", "aud2"},
  1526  		},
  1527  		{
  1528  			name: "Dex configured",
  1529  			settings: &ArgoCDSettings{DexConfig: `connectors:
  1530    - type: github
  1531      id: github
  1532      name: GitHub
  1533      config:
  1534        clientID: aabbccddeeff00112233
  1535        clientSecret: $dex.github.clientSecret
  1536        orgs:
  1537        - name: your-github-org
  1538  `},
  1539  			expected: []string{common.ArgoCDClientAppID, common.ArgoCDCLIClientAppID},
  1540  		},
  1541  	}
  1542  
  1543  	for _, tc := range testCases {
  1544  		tcc := tc
  1545  		t.Run(tcc.name, func(t *testing.T) {
  1546  			t.Parallel()
  1547  			assert.ElementsMatch(t, tcc.expected, tcc.settings.OAuth2AllowedAudiences())
  1548  		})
  1549  	}
  1550  }
  1551  
  1552  func TestReplaceStringSecret(t *testing.T) {
  1553  	secretValues := map[string]string{"my-secret-key": "my-secret-value"}
  1554  	result := ReplaceStringSecret("$my-secret-key", secretValues)
  1555  	assert.Equal(t, "my-secret-value", result)
  1556  
  1557  	result = ReplaceStringSecret("$invalid-secret-key", secretValues)
  1558  	assert.Equal(t, "$invalid-secret-key", result)
  1559  
  1560  	result = ReplaceStringSecret("", secretValues)
  1561  	assert.Equal(t, "", result)
  1562  
  1563  	result = ReplaceStringSecret("my-value", secretValues)
  1564  	assert.Equal(t, "my-value", result)
  1565  }