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

     1  package settings
     2  
     3  import (
     4  	"context"
     5  	"crypto/tls"
     6  	"crypto/x509"
     7  	"fmt"
     8  	"net/http"
     9  	"os"
    10  	"sort"
    11  	"strings"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/stretchr/testify/assert"
    16  	"github.com/stretchr/testify/require"
    17  	corev1 "k8s.io/api/core/v1"
    18  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    19  	"k8s.io/apimachinery/pkg/util/yaml"
    20  	"k8s.io/client-go/kubernetes/fake"
    21  
    22  	"github.com/argoproj/argo-cd/v3/common"
    23  	"github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
    24  	testutil "github.com/argoproj/argo-cd/v3/test"
    25  	"github.com/argoproj/argo-cd/v3/util/test"
    26  )
    27  
    28  func fixtures(data map[string]string, opts ...func(secret *corev1.Secret)) (*fake.Clientset, *SettingsManager) {
    29  	cm := &corev1.ConfigMap{
    30  		ObjectMeta: metav1.ObjectMeta{
    31  			Name:      common.ArgoCDConfigMapName,
    32  			Namespace: "default",
    33  			Labels: map[string]string{
    34  				"app.kubernetes.io/part-of": "argocd",
    35  			},
    36  		},
    37  		Data: data,
    38  	}
    39  	secret := &corev1.Secret{
    40  		ObjectMeta: metav1.ObjectMeta{
    41  			Name:      common.ArgoCDSecretName,
    42  			Namespace: "default",
    43  			Labels: map[string]string{
    44  				"app.kubernetes.io/part-of": "argocd",
    45  			},
    46  		},
    47  		Data: map[string][]byte{},
    48  	}
    49  	for i := range opts {
    50  		opts[i](secret)
    51  	}
    52  	kubeClient := fake.NewClientset(cm, secret)
    53  	settingsManager := NewSettingsManager(context.Background(), kubeClient, "default")
    54  
    55  	return kubeClient, settingsManager
    56  }
    57  
    58  func TestDocumentedArgoCDConfigMapIsValid(t *testing.T) {
    59  	var argocdCM *corev1.ConfigMap
    60  	settings := ArgoCDSettings{}
    61  	data, err := os.ReadFile("../../docs/operator-manual/argocd-cm.yaml")
    62  	require.NoError(t, err)
    63  	err = yaml.Unmarshal(data, &argocdCM)
    64  	require.NoError(t, err)
    65  	updateSettingsFromConfigMap(&settings, argocdCM)
    66  }
    67  
    68  func TestGetConfigMapByName(t *testing.T) {
    69  	t.Run("data is never nil", func(t *testing.T) {
    70  		_, settingsManager := fixtures(nil)
    71  		cm, err := settingsManager.GetConfigMapByName(common.ArgoCDConfigMapName)
    72  		require.NoError(t, err)
    73  		assert.NotNil(t, cm.Data)
    74  	})
    75  	t.Run("cannot update informer value", func(t *testing.T) {
    76  		_, settingsManager := fixtures(nil)
    77  		cm1, err := settingsManager.GetConfigMapByName(common.ArgoCDConfigMapName)
    78  		require.NoError(t, err)
    79  		cm1.Data["test"] = "invalid"
    80  		cm2, err := settingsManager.GetConfigMapByName(common.ArgoCDConfigMapName)
    81  		require.NoError(t, err)
    82  		assert.NotContains(t, cm2.Data, "test")
    83  	})
    84  }
    85  
    86  func TestGetSecretByName(t *testing.T) {
    87  	t.Run("data is never nil", func(t *testing.T) {
    88  		_, settingsManager := fixtures(nil, func(secret *corev1.Secret) { secret.Data = nil })
    89  		secret, err := settingsManager.GetSecretByName(common.ArgoCDSecretName)
    90  		require.NoError(t, err)
    91  		assert.NotNil(t, secret.Data)
    92  	})
    93  	t.Run("cannot update informer value", func(t *testing.T) {
    94  		_, settingsManager := fixtures(nil)
    95  		s1, err := settingsManager.GetSecretByName(common.ArgoCDSecretName)
    96  		require.NoError(t, err)
    97  		s1.Data["test"] = []byte("invalid")
    98  		s2, err := settingsManager.GetSecretByName(common.ArgoCDSecretName)
    99  		require.NoError(t, err)
   100  		assert.NotContains(t, s2.Data, "test")
   101  	})
   102  }
   103  
   104  func TestGetExtensionConfigs(t *testing.T) {
   105  	type cases struct {
   106  		name        string
   107  		input       map[string]string
   108  		expected    map[string]string
   109  		expectedLen int
   110  	}
   111  
   112  	testCases := []cases{
   113  		{
   114  			name:        "will return main config successfully",
   115  			expectedLen: 1,
   116  			input: map[string]string{
   117  				extensionConfig: "test",
   118  			},
   119  			expected: map[string]string{
   120  				"": "test",
   121  			},
   122  		},
   123  		{
   124  			name:        "will return main and additional config successfully",
   125  			expectedLen: 2,
   126  			input: map[string]string{
   127  				extensionConfig:                       "main config",
   128  				extensionConfig + ".anotherExtension": "another config",
   129  			},
   130  			expected: map[string]string{
   131  				"":                 "main config",
   132  				"anotherExtension": "another config",
   133  			},
   134  		},
   135  	}
   136  
   137  	for _, tc := range testCases {
   138  		tc := tc
   139  		t.Run(tc.name, func(t *testing.T) {
   140  			// When
   141  			output := getExtensionConfigs(tc.input)
   142  
   143  			// Then
   144  			assert.Len(t, output, tc.expectedLen)
   145  			assert.Equal(t, tc.expected, output)
   146  		})
   147  	}
   148  }
   149  
   150  func TestGetResourceFilter(t *testing.T) {
   151  	data := map[string]string{
   152  		"resource.exclusions": "\n  - apiGroups: [\"group1\"]\n    kinds: [\"kind1\"]\n    clusters: [\"cluster1\"]\n",
   153  		"resource.inclusions": "\n  - apiGroups: [\"group2\"]\n    kinds: [\"kind2\"]\n    clusters: [\"cluster2\"]\n",
   154  	}
   155  	_, settingsManager := fixtures(data)
   156  	filter, err := settingsManager.GetResourcesFilter()
   157  	require.NoError(t, err)
   158  	assert.Equal(t, &ResourcesFilter{
   159  		ResourceExclusions: []FilteredResource{{APIGroups: []string{"group1"}, Kinds: []string{"kind1"}, Clusters: []string{"cluster1"}}},
   160  		ResourceInclusions: []FilteredResource{{APIGroups: []string{"group2"}, Kinds: []string{"kind2"}, Clusters: []string{"cluster2"}}},
   161  	}, filter)
   162  }
   163  
   164  func TestInClusterServerAddressEnabled(t *testing.T) {
   165  	_, settingsManager := fixtures(map[string]string{
   166  		"cluster.inClusterEnabled": "true",
   167  	})
   168  	argoCDCM, err := settingsManager.getConfigMap()
   169  	require.NoError(t, err)
   170  	assert.Equal(t, "true", argoCDCM.Data[inClusterEnabledKey])
   171  
   172  	_, settingsManager = fixtures(map[string]string{
   173  		"cluster.inClusterEnabled": "false",
   174  	})
   175  	argoCDCM, err = settingsManager.getConfigMap()
   176  	require.NoError(t, err)
   177  	assert.NotEqual(t, "true", argoCDCM.Data[inClusterEnabledKey])
   178  }
   179  
   180  func TestInClusterServerAddressEnabledByDefault(t *testing.T) {
   181  	kubeClient := fake.NewClientset(
   182  		&corev1.ConfigMap{
   183  			ObjectMeta: metav1.ObjectMeta{
   184  				Name:      common.ArgoCDConfigMapName,
   185  				Namespace: "default",
   186  				Labels: map[string]string{
   187  					"app.kubernetes.io/part-of": "argocd",
   188  				},
   189  			},
   190  			Data: map[string]string{},
   191  		},
   192  		&corev1.Secret{
   193  			ObjectMeta: metav1.ObjectMeta{
   194  				Name:      common.ArgoCDSecretName,
   195  				Namespace: "default",
   196  				Labels: map[string]string{
   197  					"app.kubernetes.io/part-of": "argocd",
   198  				},
   199  			},
   200  			Data: map[string][]byte{
   201  				"admin.password":   nil,
   202  				"server.secretkey": nil,
   203  			},
   204  		},
   205  	)
   206  	settingsManager := NewSettingsManager(t.Context(), kubeClient, "default")
   207  	settings, err := settingsManager.GetSettings()
   208  	require.NoError(t, err)
   209  	assert.True(t, settings.InClusterEnabled)
   210  }
   211  
   212  func TestGetAppInstanceLabelKey(t *testing.T) {
   213  	t.Run("should get custom instanceLabelKey", func(t *testing.T) {
   214  		_, settingsManager := fixtures(map[string]string{
   215  			"application.instanceLabelKey": "testLabel",
   216  		})
   217  		label, err := settingsManager.GetAppInstanceLabelKey()
   218  		require.NoError(t, err)
   219  		assert.Equal(t, "testLabel", label)
   220  	})
   221  
   222  	t.Run("should get default instanceLabelKey if custom not defined", func(t *testing.T) {
   223  		_, settingsManager := fixtures(map[string]string{})
   224  		label, err := settingsManager.GetAppInstanceLabelKey()
   225  		require.NoError(t, err)
   226  		assert.Equal(t, common.LabelKeyAppInstance, label)
   227  	})
   228  }
   229  
   230  func TestGetTrackingMethod(t *testing.T) {
   231  	t.Run("should get custom trackingMethod", func(t *testing.T) {
   232  		_, settingsManager := fixtures(map[string]string{
   233  			"application.resourceTrackingMethod": string(v1alpha1.TrackingMethodLabel),
   234  		})
   235  		label, err := settingsManager.GetTrackingMethod()
   236  		require.NoError(t, err)
   237  		assert.Equal(t, string(v1alpha1.TrackingMethodLabel), label)
   238  	})
   239  
   240  	t.Run("should get default trackingMethod if custom not defined", func(t *testing.T) {
   241  		_, settingsManager := fixtures(map[string]string{})
   242  		label, err := settingsManager.GetTrackingMethod()
   243  		require.NoError(t, err)
   244  		assert.Equal(t, string(v1alpha1.TrackingMethodAnnotation), label)
   245  	})
   246  }
   247  
   248  func TestGetInstallationID(t *testing.T) {
   249  	_, settingsManager := fixtures(map[string]string{
   250  		"installationID": "123456789",
   251  	})
   252  	id, err := settingsManager.GetInstallationID()
   253  	require.NoError(t, err)
   254  	assert.Equal(t, "123456789", id)
   255  }
   256  
   257  func TestApplicationFineGrainedRBACInheritanceDisabledDefault(t *testing.T) {
   258  	_, settingsManager := fixtures(nil)
   259  	flag, err := settingsManager.ApplicationFineGrainedRBACInheritanceDisabled()
   260  	require.NoError(t, err)
   261  	assert.True(t, flag)
   262  }
   263  
   264  func TestApplicationFineGrainedRBACInheritanceDisabled(t *testing.T) {
   265  	_, settingsManager := fixtures(map[string]string{
   266  		"server.rbac.disableApplicationFineGrainedRBACInheritance": "false",
   267  	})
   268  	flag, err := settingsManager.ApplicationFineGrainedRBACInheritanceDisabled()
   269  	require.NoError(t, err)
   270  	assert.False(t, flag)
   271  }
   272  
   273  func TestGetIsIgnoreResourceUpdatesEnabled(t *testing.T) {
   274  	_, settingsManager := fixtures(nil)
   275  	ignoreResourceUpdatesEnabled, err := settingsManager.GetIsIgnoreResourceUpdatesEnabled()
   276  	require.NoError(t, err)
   277  	assert.True(t, ignoreResourceUpdatesEnabled)
   278  
   279  	_, settingsManager = fixtures(map[string]string{
   280  		"resource.ignoreResourceUpdatesEnabled": "true",
   281  	})
   282  	ignoreResourceUpdatesEnabled, err = settingsManager.GetIsIgnoreResourceUpdatesEnabled()
   283  	require.NoError(t, err)
   284  	assert.True(t, ignoreResourceUpdatesEnabled)
   285  }
   286  
   287  func TestGetIsIgnoreResourceUpdatesEnabledFalse(t *testing.T) {
   288  	_, settingsManager := fixtures(map[string]string{
   289  		"resource.ignoreResourceUpdatesEnabled": "false",
   290  	})
   291  	ignoreResourceUpdatesEnabled, err := settingsManager.GetIsIgnoreResourceUpdatesEnabled()
   292  	require.NoError(t, err)
   293  	assert.False(t, ignoreResourceUpdatesEnabled)
   294  }
   295  
   296  func TestGetResourceOverrides(t *testing.T) {
   297  	ignoreStatus := v1alpha1.ResourceOverride{IgnoreDifferences: v1alpha1.OverrideIgnoreDiff{
   298  		JSONPointers: []string{"/status"},
   299  	}}
   300  	crdGK := "apiextensions.k8s.io/CustomResourceDefinition"
   301  
   302  	_, settingsManager := fixtures(map[string]string{
   303  		"resource.customizations": `
   304      admissionregistration.k8s.io/MutatingWebhookConfiguration:
   305        ignoreDifferences: |
   306          jsonPointers:
   307          - /webhooks/0/clientConfig/caBundle
   308          jqPathExpressions:
   309          - .webhooks[0].clientConfig.caBundle
   310        ignoreResourceUpdates: |
   311          jsonPointers:
   312          - /webhooks/1/clientConfig/caBundle
   313          jqPathExpressions:
   314          - .webhooks[1].clientConfig.caBundle`,
   315  	})
   316  	overrides, err := settingsManager.GetResourceOverrides()
   317  	require.NoError(t, err)
   318  
   319  	webHookOverrides := overrides["admissionregistration.k8s.io/MutatingWebhookConfiguration"]
   320  	assert.NotNil(t, webHookOverrides)
   321  
   322  	assert.Equal(t, v1alpha1.ResourceOverride{
   323  		IgnoreDifferences: v1alpha1.OverrideIgnoreDiff{
   324  			JSONPointers:      []string{"/webhooks/0/clientConfig/caBundle"},
   325  			JQPathExpressions: []string{".webhooks[0].clientConfig.caBundle"},
   326  		},
   327  		IgnoreResourceUpdates: v1alpha1.OverrideIgnoreDiff{
   328  			JSONPointers:      []string{"/webhooks/1/clientConfig/caBundle"},
   329  			JQPathExpressions: []string{".webhooks[1].clientConfig.caBundle"},
   330  		},
   331  	}, webHookOverrides)
   332  
   333  	// by default, all status should be ignored
   334  	globalOverrides := overrides["*/*"]
   335  	assert.NotNil(t, globalOverrides)
   336  	assert.Equal(t, ignoreStatus, globalOverrides)
   337  
   338  	// with value all, status of all objects should be ignored
   339  	_, settingsManager = fixtures(map[string]string{
   340  		"resource.compareoptions": `
   341      ignoreResourceStatusField: all`,
   342  	})
   343  	overrides, err = settingsManager.GetResourceOverrides()
   344  	require.NoError(t, err)
   345  
   346  	globalOverrides = overrides["*/*"]
   347  	assert.NotNil(t, globalOverrides)
   348  	assert.Equal(t, ignoreStatus, globalOverrides)
   349  
   350  	// with value crd, status of crd objects should be ignored
   351  	_, settingsManager = fixtures(map[string]string{
   352  		"resource.compareoptions": `
   353      ignoreResourceStatusField: crd`,
   354  
   355  		"resource.customizations": `
   356      apiextensions.k8s.io/CustomResourceDefinition:
   357        ignoreDifferences: |
   358          jsonPointers:
   359          - /webhooks/0/clientConfig/caBundle
   360          jqPathExpressions:
   361          - .webhooks[0].clientConfig.caBundle`,
   362  	})
   363  	overrides, err = settingsManager.GetResourceOverrides()
   364  	require.NoError(t, err)
   365  
   366  	crdOverrides := overrides[crdGK]
   367  	assert.NotNil(t, crdOverrides)
   368  	assert.Equal(t, v1alpha1.ResourceOverride{IgnoreDifferences: v1alpha1.OverrideIgnoreDiff{
   369  		JSONPointers:      []string{"/webhooks/0/clientConfig/caBundle", "/status"},
   370  		JQPathExpressions: []string{".webhooks[0].clientConfig.caBundle"},
   371  	}}, crdOverrides)
   372  
   373  	// with incorrect value, status of all objects should be ignored
   374  	_, settingsManager = fixtures(map[string]string{
   375  		"resource.compareoptions": `
   376      ignoreResourceStatusField: foobar`,
   377  	})
   378  	overrides, err = settingsManager.GetResourceOverrides()
   379  	require.NoError(t, err)
   380  
   381  	globalOverrides = overrides["*/*"]
   382  	assert.NotNil(t, globalOverrides)
   383  	assert.Equal(t, ignoreStatus, globalOverrides)
   384  
   385  	// with value non-string off, status of no objects should be ignored
   386  	_, settingsManager = fixtures(map[string]string{
   387  		"resource.compareoptions": `
   388      ignoreResourceStatusField: off`,
   389  	})
   390  	overrides, err = settingsManager.GetResourceOverrides()
   391  	require.NoError(t, err)
   392  	assert.Empty(t, overrides)
   393  
   394  	// with value non-string false, status of no objects should be ignored
   395  	_, settingsManager = fixtures(map[string]string{
   396  		"resource.compareoptions": `
   397      ignoreResourceStatusField: false`,
   398  	})
   399  	overrides, err = settingsManager.GetResourceOverrides()
   400  	require.NoError(t, err)
   401  	assert.Empty(t, overrides)
   402  
   403  	// with value none, status of no objects should be ignored
   404  	_, settingsManager = fixtures(map[string]string{
   405  		"resource.compareoptions": `
   406      ignoreResourceStatusField: none`,
   407  	})
   408  	overrides, err = settingsManager.GetResourceOverrides()
   409  	require.NoError(t, err)
   410  	assert.Empty(t, overrides)
   411  }
   412  
   413  func TestGetResourceOverridesHealthWithWildcard(t *testing.T) {
   414  	data := map[string]string{
   415  		"resource.customizations": `
   416      "*.aws.crossplane.io/*":
   417        health.lua: |
   418          foo`,
   419  	}
   420  
   421  	t.Run("TestResourceHealthOverrideWithWildcard", func(t *testing.T) {
   422  		_, settingsManager := fixtures(data)
   423  
   424  		overrides, err := settingsManager.GetResourceOverrides()
   425  		require.NoError(t, err)
   426  		assert.Len(t, overrides, 2)
   427  		assert.Equal(t, "foo", overrides["*.aws.crossplane.io/*"].HealthLua)
   428  	})
   429  }
   430  
   431  func TestSettingsManager_GetResourceOverrides_with_empty_string(t *testing.T) {
   432  	_, settingsManager := fixtures(map[string]string{
   433  		resourceCustomizationsKey: "",
   434  	})
   435  	overrides, err := settingsManager.GetResourceOverrides()
   436  	require.NoError(t, err)
   437  
   438  	assert.Len(t, overrides, 1)
   439  }
   440  
   441  func TestGetResourceOverrides_with_splitted_keys(t *testing.T) {
   442  	data := map[string]string{
   443  		"resource.compareoptions": `ignoreResourceStatusField: none`,
   444  
   445  		"resource.customizations": `
   446      admissionregistration.k8s.io/MutatingWebhookConfiguration:
   447        ignoreDifferences: |
   448          jsonPointers:
   449          - foo
   450        ignoreResourceUpdates: |
   451          jsonPointers:
   452          - foo
   453      certmanager.k8s.io/Certificate:
   454        health.lua.useOpenLibs: true
   455        health.lua: |
   456          foo
   457      cert-manager.io/Certificate:
   458        health.lua: |
   459          foo
   460      apps/Deployment:
   461        actions: |
   462          foo`,
   463  	}
   464  
   465  	t.Run("MergedKey", func(t *testing.T) {
   466  		_, settingsManager := fixtures(data)
   467  
   468  		overrides, err := settingsManager.GetResourceOverrides()
   469  		require.NoError(t, err)
   470  		assert.Len(t, overrides, 4)
   471  		assert.Len(t, overrides["admissionregistration.k8s.io/MutatingWebhookConfiguration"].IgnoreDifferences.JSONPointers, 1)
   472  		assert.Equal(t, "foo", overrides["admissionregistration.k8s.io/MutatingWebhookConfiguration"].IgnoreDifferences.JSONPointers[0])
   473  		assert.Len(t, overrides["admissionregistration.k8s.io/MutatingWebhookConfiguration"].IgnoreResourceUpdates.JSONPointers, 1)
   474  		assert.Equal(t, "foo", overrides["admissionregistration.k8s.io/MutatingWebhookConfiguration"].IgnoreResourceUpdates.JSONPointers[0])
   475  		assert.Equal(t, "foo\n", overrides["certmanager.k8s.io/Certificate"].HealthLua)
   476  		assert.True(t, overrides["certmanager.k8s.io/Certificate"].UseOpenLibs)
   477  		assert.Equal(t, "foo\n", overrides["cert-manager.io/Certificate"].HealthLua)
   478  		assert.False(t, overrides["cert-manager.io/Certificate"].UseOpenLibs)
   479  		assert.Equal(t, "foo", overrides["apps/Deployment"].Actions)
   480  	})
   481  
   482  	t.Run("SplitKeys", func(t *testing.T) {
   483  		newData := map[string]string{
   484  			"resource.compareoptions": `ignoreResourceStatusField: none`,
   485  
   486  			"resource.customizations.health.admissionregistration.k8s.io_MutatingWebhookConfiguration": "bar",
   487  			"resource.customizations.ignoreDifferences.admissionregistration.k8s.io_MutatingWebhookConfiguration": `jsonPointers:
   488          - bar`,
   489  			"resource.customizations.ignoreResourceUpdates.admissionregistration.k8s.io_MutatingWebhookConfiguration": `jsonPointers:
   490          - bar`,
   491  			"resource.customizations.knownTypeFields.admissionregistration.k8s.io_MutatingWebhookConfiguration": `
   492  - field: foo
   493    type: bar`,
   494  			"resource.customizations.health.certmanager.k8s.io_Certificate":      "bar",
   495  			"resource.customizations.health.cert-manager.io_Certificate":         "bar",
   496  			"resource.customizations.useOpenLibs.certmanager.k8s.io_Certificate": "false",
   497  			"resource.customizations.useOpenLibs.cert-manager.io_Certificate":    "true",
   498  			"resource.customizations.actions.apps_Deployment":                    "bar",
   499  			"resource.customizations.actions.Deployment":                         "bar",
   500  			"resource.customizations.health.iam-manager.k8s.io_Iamrole":          "bar",
   501  			"resource.customizations.health.Iamrole":                             "bar",
   502  			"resource.customizations.ignoreDifferences.iam-manager.k8s.io_Iamrole": `jsonPointers:
   503          - bar`,
   504  			"resource.customizations.ignoreDifferences.apps_Deployment": `jqPathExpressions:
   505          - bar`,
   506  			"resource.customizations.ignoreDifferences.all": `managedFieldsManagers:
   507          - kube-controller-manager
   508          - argo-rollouts`,
   509  			"resource.customizations.ignoreResourceUpdates.iam-manager.k8s.io_Iamrole": `jsonPointers:
   510          - bar`,
   511  			"resource.customizations.ignoreResourceUpdates.apps_Deployment": `jqPathExpressions:
   512          - bar`,
   513  		}
   514  
   515  		_, settingsManager := fixtures(mergemaps(data, newData))
   516  
   517  		overrides, err := settingsManager.GetResourceOverrides()
   518  		require.NoError(t, err)
   519  		assert.Len(t, overrides, 8)
   520  		assert.Len(t, overrides["admissionregistration.k8s.io/MutatingWebhookConfiguration"].IgnoreDifferences.JSONPointers, 1)
   521  		assert.Equal(t, "bar", overrides["admissionregistration.k8s.io/MutatingWebhookConfiguration"].IgnoreDifferences.JSONPointers[0])
   522  		assert.Len(t, overrides["admissionregistration.k8s.io/MutatingWebhookConfiguration"].IgnoreResourceUpdates.JSONPointers, 1)
   523  		assert.Equal(t, "bar", overrides["admissionregistration.k8s.io/MutatingWebhookConfiguration"].IgnoreResourceUpdates.JSONPointers[0])
   524  		assert.Len(t, overrides["admissionregistration.k8s.io/MutatingWebhookConfiguration"].KnownTypeFields, 1)
   525  		assert.Equal(t, "bar", overrides["admissionregistration.k8s.io/MutatingWebhookConfiguration"].KnownTypeFields[0].Type)
   526  		assert.Equal(t, "bar", overrides["admissionregistration.k8s.io/MutatingWebhookConfiguration"].HealthLua)
   527  		assert.Equal(t, "bar", overrides["certmanager.k8s.io/Certificate"].HealthLua)
   528  		assert.Equal(t, "bar", overrides["cert-manager.io/Certificate"].HealthLua)
   529  		assert.False(t, overrides["certmanager.k8s.io/Certificate"].UseOpenLibs)
   530  		assert.True(t, overrides["cert-manager.io/Certificate"].UseOpenLibs)
   531  		assert.Equal(t, "bar", overrides["apps/Deployment"].Actions)
   532  		assert.Equal(t, "bar", overrides["Deployment"].Actions)
   533  		assert.Equal(t, "bar", overrides["iam-manager.k8s.io/Iamrole"].HealthLua)
   534  		assert.Equal(t, "bar", overrides["Iamrole"].HealthLua)
   535  		assert.Len(t, overrides["iam-manager.k8s.io/Iamrole"].IgnoreDifferences.JSONPointers, 1)
   536  		assert.Len(t, overrides["apps/Deployment"].IgnoreDifferences.JQPathExpressions, 1)
   537  		assert.Equal(t, "bar", overrides["apps/Deployment"].IgnoreDifferences.JQPathExpressions[0])
   538  		assert.Len(t, overrides["*/*"].IgnoreDifferences.ManagedFieldsManagers, 2)
   539  		assert.Equal(t, "kube-controller-manager", overrides["*/*"].IgnoreDifferences.ManagedFieldsManagers[0])
   540  		assert.Equal(t, "argo-rollouts", overrides["*/*"].IgnoreDifferences.ManagedFieldsManagers[1])
   541  		assert.Len(t, overrides["iam-manager.k8s.io/Iamrole"].IgnoreResourceUpdates.JSONPointers, 1)
   542  		assert.Len(t, overrides["apps/Deployment"].IgnoreResourceUpdates.JQPathExpressions, 1)
   543  		assert.Equal(t, "bar", overrides["apps/Deployment"].IgnoreResourceUpdates.JQPathExpressions[0])
   544  	})
   545  }
   546  
   547  func mergemaps(mapA map[string]string, mapB map[string]string) map[string]string {
   548  	for k, v := range mapA {
   549  		mapB[k] = v
   550  	}
   551  	return mapB
   552  }
   553  
   554  func TestGetIgnoreResourceUpdatesOverrides(t *testing.T) {
   555  	allDefault := v1alpha1.ResourceOverride{IgnoreDifferences: v1alpha1.OverrideIgnoreDiff{
   556  		JSONPointers: []string{"/metadata/resourceVersion", "/metadata/generation", "/metadata/managedFields"},
   557  	}}
   558  	allGK := "*/*"
   559  
   560  	testCustomizations := map[string]string{
   561  		"resource.compareoptions": `
   562              ignoreResourceStatusField: none
   563              ignoreDifferencesOnResourceUpdates: true`,
   564  
   565  		"resource.customizations": `
   566      admissionregistration.k8s.io/MutatingWebhookConfiguration:
   567        ignoreDifferences: |
   568          jsonPointers:
   569          - /webhooks/0/clientConfig/caBundle
   570          jqPathExpressions:
   571          - .webhooks[0].clientConfig.caBundle
   572        ignoreResourceUpdates: |
   573          jsonPointers:
   574          - /webhooks/1/clientConfig/caBundle
   575          jqPathExpressions:
   576          - .webhooks[1].clientConfig.caBundle`,
   577  	}
   578  
   579  	_, settingsManager := fixtures(testCustomizations)
   580  	overrides, err := settingsManager.GetIgnoreResourceUpdatesOverrides()
   581  	require.NoError(t, err)
   582  
   583  	// default overrides should always be present
   584  	allOverrides := overrides[allGK]
   585  	assert.NotNil(t, allOverrides)
   586  	assert.Equal(t, allDefault, allOverrides)
   587  
   588  	// with ignoreDifferencesOnResourceUpdates, ignoreDifferences should be added
   589  	assert.NotNil(t, overrides["admissionregistration.k8s.io/MutatingWebhookConfiguration"])
   590  	assert.Equal(t, v1alpha1.ResourceOverride{
   591  		IgnoreDifferences: v1alpha1.OverrideIgnoreDiff{
   592  			JSONPointers:      []string{"/webhooks/1/clientConfig/caBundle", "/webhooks/0/clientConfig/caBundle"},
   593  			JQPathExpressions: []string{".webhooks[1].clientConfig.caBundle", ".webhooks[0].clientConfig.caBundle"},
   594  		},
   595  		IgnoreResourceUpdates: v1alpha1.OverrideIgnoreDiff{},
   596  	}, overrides["admissionregistration.k8s.io/MutatingWebhookConfiguration"])
   597  
   598  	// without ignoreDifferencesOnResourceUpdates, only ignoreResourceUpdates should be added
   599  	_, settingsManager = fixtures(mergemaps(map[string]string{
   600  		"resource.compareoptions": `
   601              ignoreResourceStatusField: none
   602              ignoreDifferencesOnResourceUpdates: false`,
   603  	}, testCustomizations))
   604  	overrides, err = settingsManager.GetIgnoreResourceUpdatesOverrides()
   605  	require.NoError(t, err)
   606  	assert.NotNil(t, overrides["admissionregistration.k8s.io/MutatingWebhookConfiguration"])
   607  	assert.Equal(t, v1alpha1.ResourceOverride{
   608  		IgnoreDifferences: v1alpha1.OverrideIgnoreDiff{
   609  			JSONPointers:      []string{"/webhooks/1/clientConfig/caBundle"},
   610  			JQPathExpressions: []string{".webhooks[1].clientConfig.caBundle"},
   611  		},
   612  		IgnoreResourceUpdates: v1alpha1.OverrideIgnoreDiff{},
   613  	}, overrides["admissionregistration.k8s.io/MutatingWebhookConfiguration"])
   614  }
   615  
   616  func TestConvertToOverrideKey(t *testing.T) {
   617  	key, err := convertToOverrideKey("cert-manager.io_Certificate")
   618  	require.NoError(t, err)
   619  	assert.Equal(t, "cert-manager.io/Certificate", key)
   620  
   621  	key, err = convertToOverrideKey("Certificate")
   622  	require.NoError(t, err)
   623  	assert.Equal(t, "Certificate", key)
   624  
   625  	_, err = convertToOverrideKey("")
   626  	require.Error(t, err)
   627  
   628  	_, err = convertToOverrideKey("_")
   629  	require.NoError(t, err)
   630  }
   631  
   632  func TestGetResourceCompareOptions(t *testing.T) {
   633  	// ignoreAggregatedRules is true
   634  	{
   635  		_, settingsManager := fixtures(map[string]string{
   636  			"resource.compareoptions": "ignoreAggregatedRoles: true",
   637  		})
   638  		compareOptions, err := settingsManager.GetResourceCompareOptions()
   639  		require.NoError(t, err)
   640  		assert.True(t, compareOptions.IgnoreAggregatedRoles)
   641  	}
   642  
   643  	// ignoreAggregatedRules is false
   644  	{
   645  		_, settingsManager := fixtures(map[string]string{
   646  			"resource.compareoptions": "ignoreAggregatedRoles: false",
   647  		})
   648  		compareOptions, err := settingsManager.GetResourceCompareOptions()
   649  		require.NoError(t, err)
   650  		assert.False(t, compareOptions.IgnoreAggregatedRoles)
   651  	}
   652  
   653  	// ignoreDifferencesOnResourceUpdates is true
   654  	{
   655  		_, settingsManager := fixtures(map[string]string{
   656  			"resource.compareoptions": "ignoreDifferencesOnResourceUpdates: true",
   657  		})
   658  		compareOptions, err := settingsManager.GetResourceCompareOptions()
   659  		require.NoError(t, err)
   660  		assert.True(t, compareOptions.IgnoreDifferencesOnResourceUpdates)
   661  	}
   662  
   663  	// ignoreDifferencesOnResourceUpdates is false
   664  	{
   665  		_, settingsManager := fixtures(map[string]string{
   666  			"resource.compareoptions": "ignoreDifferencesOnResourceUpdates: false",
   667  		})
   668  		compareOptions, err := settingsManager.GetResourceCompareOptions()
   669  		require.NoError(t, err)
   670  		assert.False(t, compareOptions.IgnoreDifferencesOnResourceUpdates)
   671  	}
   672  
   673  	// The empty resource.compareoptions should result in default being returned
   674  	{
   675  		_, settingsManager := fixtures(map[string]string{
   676  			"resource.compareoptions": "",
   677  		})
   678  		compareOptions, err := settingsManager.GetResourceCompareOptions()
   679  		defaultOptions := GetDefaultDiffOptions()
   680  		require.NoError(t, err)
   681  		assert.Equal(t, defaultOptions.IgnoreAggregatedRoles, compareOptions.IgnoreAggregatedRoles)
   682  		assert.Equal(t, defaultOptions.IgnoreDifferencesOnResourceUpdates, compareOptions.IgnoreDifferencesOnResourceUpdates)
   683  	}
   684  
   685  	// resource.compareoptions not defined - should result in default being returned
   686  	{
   687  		_, settingsManager := fixtures(map[string]string{})
   688  		compareOptions, err := settingsManager.GetResourceCompareOptions()
   689  		defaultOptions := GetDefaultDiffOptions()
   690  		require.NoError(t, err)
   691  		assert.Equal(t, defaultOptions.IgnoreAggregatedRoles, compareOptions.IgnoreAggregatedRoles)
   692  		assert.Equal(t, defaultOptions.IgnoreDifferencesOnResourceUpdates, compareOptions.IgnoreDifferencesOnResourceUpdates)
   693  	}
   694  }
   695  
   696  func TestSettingsManager_GetKustomizeBuildOptions(t *testing.T) {
   697  	t.Run("Empty", func(t *testing.T) {
   698  		_, settingsManager := fixtures(map[string]string{})
   699  
   700  		settings, err := settingsManager.GetKustomizeSettings()
   701  
   702  		require.NoError(t, err)
   703  		assert.Empty(t, settings.BuildOptions)
   704  		assert.Empty(t, settings.Versions)
   705  	})
   706  	t.Run("Set", func(t *testing.T) {
   707  		_, settingsManager := fixtures(map[string]string{
   708  			"kustomize.buildOptions":   "foo",
   709  			"kustomize.version.v3.2.1": "somePath",
   710  		})
   711  
   712  		options, err := settingsManager.GetKustomizeSettings()
   713  
   714  		require.NoError(t, err)
   715  		assert.Equal(t, "foo", options.BuildOptions)
   716  		assert.Equal(t, []v1alpha1.KustomizeVersion{{Name: "v3.2.1", Path: "somePath"}}, options.Versions)
   717  	})
   718  
   719  	t.Run("Kustomize settings per-version", func(t *testing.T) {
   720  		_, settingsManager := fixtures(map[string]string{
   721  			"kustomize.buildOptions":        "--global true",
   722  			"kustomize.version.v3.2.1":      "/path_3.2.1",
   723  			"kustomize.buildOptions.v3.2.3": "--options v3.2.3",
   724  			"kustomize.path.v3.2.3":         "/path_3.2.3",
   725  			"kustomize.path.v3.2.4":         "/path_3.2.4",
   726  			"kustomize.buildOptions.v3.2.4": "--options v3.2.4",
   727  			"kustomize.buildOptions.v3.2.5": "--options v3.2.5",
   728  		})
   729  
   730  		got, err := settingsManager.GetKustomizeSettings()
   731  
   732  		require.NoError(t, err)
   733  		assert.Equal(t, "--global true", got.BuildOptions)
   734  		want := &v1alpha1.KustomizeOptions{
   735  			BuildOptions: "--global true",
   736  			Versions: []v1alpha1.KustomizeVersion{
   737  				{Name: "v3.2.1", Path: "/path_3.2.1"},
   738  				{Name: "v3.2.3", Path: "/path_3.2.3", BuildOptions: "--options v3.2.3"},
   739  				{Name: "v3.2.4", Path: "/path_3.2.4", BuildOptions: "--options v3.2.4"},
   740  			},
   741  		}
   742  		sortVersionsByName := func(versions []v1alpha1.KustomizeVersion) {
   743  			sort.Slice(versions, func(i, j int) bool {
   744  				return versions[i].Name > versions[j].Name
   745  			})
   746  		}
   747  		sortVersionsByName(want.Versions)
   748  		sortVersionsByName(got.Versions)
   749  		assert.Equal(t, want, got)
   750  	})
   751  
   752  	t.Run("Kustomize settings per-version with duplicate versions", func(t *testing.T) {
   753  		_, settingsManager := fixtures(map[string]string{
   754  			"kustomize.buildOptions":        "--global true",
   755  			"kustomize.version.v3.2.1":      "/path_3.2.1",
   756  			"kustomize.buildOptions.v3.2.1": "--options v3.2.3",
   757  			"kustomize.path.v3.2.2":         "/other_path_3.2.2",
   758  			"kustomize.path.v3.2.1":         "/other_path_3.2.1",
   759  		})
   760  
   761  		got, err := settingsManager.GetKustomizeSettings()
   762  		require.ErrorContains(t, err, "found duplicate kustomize version: v3.2.1")
   763  		assert.Empty(t, got)
   764  	})
   765  
   766  	t.Run("Config map with no Kustomize settings", func(t *testing.T) {
   767  		_, settingsManager := fixtures(map[string]string{
   768  			"other.options": "--global true",
   769  		})
   770  
   771  		got, err := settingsManager.GetKustomizeSettings()
   772  		require.NoError(t, err)
   773  		assert.Empty(t, got)
   774  	})
   775  }
   776  
   777  func TestSettingsManager_GetEventLabelKeys(t *testing.T) {
   778  	tests := []struct {
   779  		name         string
   780  		data         string
   781  		expectedKeys []string
   782  	}{
   783  		{
   784  			name:         "Comma separated data",
   785  			data:         "app,env, tier,    example.com/team-*, *",
   786  			expectedKeys: []string{"app", "env", "tier", "example.com/team-*", "*"},
   787  		},
   788  		{
   789  			name:         "Empty data",
   790  			expectedKeys: []string{},
   791  		},
   792  	}
   793  	for _, tt := range tests {
   794  		t.Run(tt.name, func(t *testing.T) {
   795  			_, settingsManager := fixtures(map[string]string{})
   796  			if tt.data != "" {
   797  				_, settingsManager = fixtures(map[string]string{
   798  					resourceIncludeEventLabelKeys: tt.data,
   799  					resourceExcludeEventLabelKeys: tt.data,
   800  				})
   801  			}
   802  
   803  			inKeys := settingsManager.GetIncludeEventLabelKeys()
   804  			assert.Len(t, inKeys, len(tt.expectedKeys))
   805  
   806  			exKeys := settingsManager.GetExcludeEventLabelKeys()
   807  			assert.Len(t, exKeys, len(tt.expectedKeys))
   808  
   809  			for i := range tt.expectedKeys {
   810  				assert.Equal(t, tt.expectedKeys[i], inKeys[i])
   811  				assert.Equal(t, tt.expectedKeys[i], exKeys[i])
   812  			}
   813  		})
   814  	}
   815  }
   816  
   817  func Test_GetKustomizeBinaryPath(t *testing.T) {
   818  	ko := &v1alpha1.KustomizeOptions{
   819  		BuildOptions: "--opt1 val1",
   820  		Versions: []v1alpha1.KustomizeVersion{
   821  			{Name: "v1", Path: "path_v1"},
   822  			{Name: "v2", Path: "path_v2"},
   823  			{Name: "v3", Path: "path_v3", BuildOptions: "--opt2 val2"},
   824  		},
   825  	}
   826  
   827  	t.Run("VersionDoesNotExist", func(t *testing.T) {
   828  		_, err := GetKustomizeBinaryPath(ko, v1alpha1.ApplicationSource{
   829  			Kustomize: &v1alpha1.ApplicationSourceKustomize{Version: "v4"},
   830  		})
   831  		require.Error(t, err)
   832  	})
   833  
   834  	t.Run("DefaultBuildOptions", func(t *testing.T) {
   835  		ver, err := GetKustomizeBinaryPath(ko, v1alpha1.ApplicationSource{})
   836  		require.NoError(t, err)
   837  		assert.Empty(t, ver)
   838  	})
   839  
   840  	t.Run("VersionExists", func(t *testing.T) {
   841  		ver, err := GetKustomizeBinaryPath(ko, v1alpha1.ApplicationSource{
   842  			Kustomize: &v1alpha1.ApplicationSourceKustomize{Version: "v2"},
   843  		})
   844  		require.NoError(t, err)
   845  		assert.Equal(t, "path_v2", ver)
   846  	})
   847  
   848  	t.Run("VersionExistsWithBuildOption", func(t *testing.T) {
   849  		ver, err := GetKustomizeBinaryPath(ko, v1alpha1.ApplicationSource{
   850  			Kustomize: &v1alpha1.ApplicationSourceKustomize{Version: "v3"},
   851  		})
   852  		require.NoError(t, err)
   853  		assert.Equal(t, "path_v3", ver)
   854  	})
   855  
   856  	t.Run("ExplicitVersionSet", func(t *testing.T) {
   857  		// nolint:staticcheck // test for backwards compatibility with deprecated field
   858  		ko.BinaryPath = "custom_path"
   859  		ver, err := GetKustomizeBinaryPath(ko, v1alpha1.ApplicationSource{
   860  			Kustomize: &v1alpha1.ApplicationSourceKustomize{Version: "v3"},
   861  		})
   862  		require.NoError(t, err)
   863  		assert.Equal(t, "custom_path", ver)
   864  	})
   865  }
   866  
   867  func TestGetGoogleAnalytics(t *testing.T) {
   868  	_, settingsManager := fixtures(map[string]string{
   869  		"ga.trackingid": "123",
   870  	})
   871  	ga, err := settingsManager.GetGoogleAnalytics()
   872  	require.NoError(t, err)
   873  	assert.Equal(t, "123", ga.TrackingID)
   874  	assert.True(t, ga.AnonymizeUsers)
   875  }
   876  
   877  func TestSettingsManager_GetHelp(t *testing.T) {
   878  	t.Run("Default", func(t *testing.T) {
   879  		_, settingsManager := fixtures(nil)
   880  		h, err := settingsManager.GetHelp()
   881  		require.NoError(t, err)
   882  		assert.Empty(t, h.ChatURL)
   883  		assert.Empty(t, h.ChatText)
   884  	})
   885  	t.Run("Set", func(t *testing.T) {
   886  		_, settingsManager := fixtures(map[string]string{
   887  			"help.chatUrl":  "foo",
   888  			"help.chatText": "bar",
   889  		})
   890  		h, err := settingsManager.GetHelp()
   891  		require.NoError(t, err)
   892  		assert.Equal(t, "foo", h.ChatURL)
   893  		assert.Equal(t, "bar", h.ChatText)
   894  	})
   895  	t.Run("SetOnlyChatUrl", func(t *testing.T) {
   896  		_, settingManager := fixtures(map[string]string{
   897  			"help.chatUrl": "foo",
   898  		})
   899  		h, err := settingManager.GetHelp()
   900  		require.NoError(t, err)
   901  		assert.Equal(t, "foo", h.ChatURL)
   902  		assert.Equal(t, "Chat now!", h.ChatText)
   903  	})
   904  	t.Run("SetOnlyChatText", func(t *testing.T) {
   905  		_, settingManager := fixtures(map[string]string{
   906  			"help.chatText": "bar",
   907  		})
   908  		h, err := settingManager.GetHelp()
   909  		require.NoError(t, err)
   910  		assert.Empty(t, h.ChatURL)
   911  		assert.Empty(t, h.ChatText)
   912  	})
   913  	t.Run("GetBinaryUrls", func(t *testing.T) {
   914  		_, settingsManager := fixtures(map[string]string{
   915  			"help.download.darwin-amd64": "amd64-path",
   916  			"help.download.linux-s390x":  "s390x-path",
   917  			"help.download.unsupported":  "nowhere",
   918  		})
   919  		h, err := settingsManager.GetHelp()
   920  		require.NoError(t, err)
   921  		assert.Equal(t, map[string]string{"darwin-amd64": "amd64-path", "linux-s390x": "s390x-path"}, h.BinaryURLs)
   922  	})
   923  }
   924  
   925  func TestSettingsManager_GetSettings(t *testing.T) {
   926  	t.Run("UserSessionDurationNotProvided", func(t *testing.T) {
   927  		kubeClient := fake.NewClientset(
   928  			&corev1.ConfigMap{
   929  				ObjectMeta: metav1.ObjectMeta{
   930  					Name:      common.ArgoCDConfigMapName,
   931  					Namespace: "default",
   932  					Labels: map[string]string{
   933  						"app.kubernetes.io/part-of": "argocd",
   934  					},
   935  				},
   936  				Data: nil,
   937  			},
   938  			&corev1.Secret{
   939  				ObjectMeta: metav1.ObjectMeta{
   940  					Name:      common.ArgoCDSecretName,
   941  					Namespace: "default",
   942  					Labels: map[string]string{
   943  						"app.kubernetes.io/part-of": "argocd",
   944  					},
   945  				},
   946  				Data: map[string][]byte{
   947  					"server.secretkey": nil,
   948  				},
   949  			},
   950  		)
   951  		settingsManager := NewSettingsManager(t.Context(), kubeClient, "default")
   952  		s, err := settingsManager.GetSettings()
   953  		require.NoError(t, err)
   954  		assert.Equal(t, time.Hour*24, s.UserSessionDuration)
   955  	})
   956  	t.Run("UserSessionDurationInvalidFormat", func(t *testing.T) {
   957  		kubeClient := fake.NewClientset(
   958  			&corev1.ConfigMap{
   959  				ObjectMeta: metav1.ObjectMeta{
   960  					Name:      common.ArgoCDConfigMapName,
   961  					Namespace: "default",
   962  					Labels: map[string]string{
   963  						"app.kubernetes.io/part-of": "argocd",
   964  					},
   965  				},
   966  				Data: map[string]string{
   967  					"users.session.duration": "10hh",
   968  				},
   969  			},
   970  			&corev1.Secret{
   971  				ObjectMeta: metav1.ObjectMeta{
   972  					Name:      common.ArgoCDSecretName,
   973  					Namespace: "default",
   974  					Labels: map[string]string{
   975  						"app.kubernetes.io/part-of": "argocd",
   976  					},
   977  				},
   978  				Data: map[string][]byte{
   979  					"server.secretkey": nil,
   980  				},
   981  			},
   982  		)
   983  		settingsManager := NewSettingsManager(t.Context(), kubeClient, "default")
   984  		s, err := settingsManager.GetSettings()
   985  		require.NoError(t, err)
   986  		assert.Equal(t, time.Hour*24, s.UserSessionDuration)
   987  	})
   988  	t.Run("UserSessionDurationProvided", func(t *testing.T) {
   989  		kubeClient := fake.NewClientset(
   990  			&corev1.ConfigMap{
   991  				ObjectMeta: metav1.ObjectMeta{
   992  					Name:      common.ArgoCDConfigMapName,
   993  					Namespace: "default",
   994  					Labels: map[string]string{
   995  						"app.kubernetes.io/part-of": "argocd",
   996  					},
   997  				},
   998  				Data: map[string]string{
   999  					"users.session.duration": "10h",
  1000  				},
  1001  			},
  1002  			&corev1.Secret{
  1003  				ObjectMeta: metav1.ObjectMeta{
  1004  					Name:      common.ArgoCDSecretName,
  1005  					Namespace: "default",
  1006  					Labels: map[string]string{
  1007  						"app.kubernetes.io/part-of": "argocd",
  1008  					},
  1009  				},
  1010  				Data: map[string][]byte{
  1011  					"server.secretkey": nil,
  1012  				},
  1013  			},
  1014  		)
  1015  		settingsManager := NewSettingsManager(t.Context(), kubeClient, "default")
  1016  		s, err := settingsManager.GetSettings()
  1017  		require.NoError(t, err)
  1018  		assert.Equal(t, time.Hour*10, s.UserSessionDuration)
  1019  	})
  1020  }
  1021  
  1022  func TestGetOIDCConfig(t *testing.T) {
  1023  	kubeClient := fake.NewClientset(
  1024  		&corev1.ConfigMap{
  1025  			ObjectMeta: metav1.ObjectMeta{
  1026  				Name:      common.ArgoCDConfigMapName,
  1027  				Namespace: "default",
  1028  				Labels: map[string]string{
  1029  					"app.kubernetes.io/part-of": "argocd",
  1030  				},
  1031  			},
  1032  			Data: map[string]string{
  1033  				"oidc.config": "\n  requestedIDTokenClaims: {\"groups\": {\"essential\": true}}\n",
  1034  			},
  1035  		},
  1036  		&corev1.Secret{
  1037  			ObjectMeta: metav1.ObjectMeta{
  1038  				Name:      common.ArgoCDSecretName,
  1039  				Namespace: "default",
  1040  				Labels: map[string]string{
  1041  					"app.kubernetes.io/part-of": "argocd",
  1042  				},
  1043  			},
  1044  			Data: map[string][]byte{
  1045  				"admin.password":   nil,
  1046  				"server.secretkey": nil,
  1047  			},
  1048  		},
  1049  	)
  1050  	settingsManager := NewSettingsManager(t.Context(), kubeClient, "default")
  1051  	settings, err := settingsManager.GetSettings()
  1052  	require.NoError(t, err)
  1053  
  1054  	oidcConfig := settings.OIDCConfig()
  1055  	assert.NotNil(t, oidcConfig)
  1056  
  1057  	claim := oidcConfig.RequestedIDTokenClaims["groups"]
  1058  	assert.NotNil(t, claim)
  1059  	assert.True(t, claim.Essential)
  1060  }
  1061  
  1062  func TestRedirectURL(t *testing.T) {
  1063  	cases := map[string][]string{
  1064  		"https://localhost:4000":         {"https://localhost:4000/auth/callback", "https://localhost:4000/api/dex/callback"},
  1065  		"https://localhost:4000/":        {"https://localhost:4000/auth/callback", "https://localhost:4000/api/dex/callback"},
  1066  		"https://localhost:4000/argocd":  {"https://localhost:4000/argocd/auth/callback", "https://localhost:4000/argocd/api/dex/callback"},
  1067  		"https://localhost:4000/argocd/": {"https://localhost:4000/argocd/auth/callback", "https://localhost:4000/argocd/api/dex/callback"},
  1068  	}
  1069  	for given, expected := range cases {
  1070  		settings := ArgoCDSettings{URL: given}
  1071  		redirectURL, err := settings.RedirectURL()
  1072  		require.NoError(t, err)
  1073  		assert.Equal(t, expected[0], redirectURL)
  1074  		dexRedirectURL, err := settings.DexRedirectURL()
  1075  		require.NoError(t, err)
  1076  		assert.Equal(t, expected[1], dexRedirectURL)
  1077  	}
  1078  }
  1079  
  1080  func Test_validateExternalURL(t *testing.T) {
  1081  	tests := []struct {
  1082  		name   string
  1083  		url    string
  1084  		errMsg string
  1085  	}{
  1086  		{name: "Valid URL", url: "https://my.domain.com"},
  1087  		{name: "No URL - Valid", url: ""},
  1088  		{name: "Invalid URL", url: "my.domain.com", errMsg: "URL must include http or https protocol"},
  1089  	}
  1090  	for _, tt := range tests {
  1091  		t.Run(tt.name, func(t *testing.T) {
  1092  			err := validateExternalURL(tt.url)
  1093  			if tt.errMsg != "" {
  1094  				assert.EqualError(t, err, tt.errMsg)
  1095  			} else {
  1096  				require.NoError(t, err)
  1097  			}
  1098  		})
  1099  	}
  1100  }
  1101  
  1102  func TestGetOIDCSecretTrim(t *testing.T) {
  1103  	kubeClient := fake.NewClientset(
  1104  		&corev1.ConfigMap{
  1105  			ObjectMeta: metav1.ObjectMeta{
  1106  				Name:      common.ArgoCDConfigMapName,
  1107  				Namespace: "default",
  1108  				Labels: map[string]string{
  1109  					"app.kubernetes.io/part-of": "argocd",
  1110  				},
  1111  			},
  1112  			Data: map[string]string{
  1113  				"oidc.config": "\n  name: Okta\n  clientSecret: test-secret\r\n \n  clientID: aaaabbbbccccddddeee\n",
  1114  			},
  1115  		},
  1116  		&corev1.Secret{
  1117  			ObjectMeta: metav1.ObjectMeta{
  1118  				Name:      common.ArgoCDSecretName,
  1119  				Namespace: "default",
  1120  				Labels: map[string]string{
  1121  					"app.kubernetes.io/part-of": "argocd",
  1122  				},
  1123  			},
  1124  			Data: map[string][]byte{
  1125  				"admin.password":   nil,
  1126  				"server.secretkey": nil,
  1127  			},
  1128  		},
  1129  	)
  1130  	settingsManager := NewSettingsManager(t.Context(), kubeClient, "default")
  1131  	settings, err := settingsManager.GetSettings()
  1132  	require.NoError(t, err)
  1133  
  1134  	oidcConfig := settings.OIDCConfig()
  1135  	assert.NotNil(t, oidcConfig)
  1136  	assert.Equal(t, "test-secret", oidcConfig.ClientSecret)
  1137  }
  1138  
  1139  func getCNFromCertificate(cert *tls.Certificate) string {
  1140  	c, err := x509.ParseCertificate(cert.Certificate[0])
  1141  	if err != nil {
  1142  		return ""
  1143  	}
  1144  	return c.Subject.CommonName
  1145  }
  1146  
  1147  func Test_GetTLSConfiguration(t *testing.T) {
  1148  	t.Run("Valid external TLS secret with success", func(t *testing.T) {
  1149  		kubeClient := fake.NewClientset(
  1150  			&corev1.ConfigMap{
  1151  				ObjectMeta: metav1.ObjectMeta{
  1152  					Name:      common.ArgoCDConfigMapName,
  1153  					Namespace: "default",
  1154  					Labels: map[string]string{
  1155  						"app.kubernetes.io/part-of": "argocd",
  1156  					},
  1157  				},
  1158  				Data: map[string]string{
  1159  					"oidc.config": "\n  name: Okta\n  clientSecret: test-secret\r\n \n  clientID: aaaabbbbccccddddeee\n",
  1160  				},
  1161  			},
  1162  			&corev1.Secret{
  1163  				ObjectMeta: metav1.ObjectMeta{
  1164  					Name:      common.ArgoCDSecretName,
  1165  					Namespace: "default",
  1166  					Labels: map[string]string{
  1167  						"app.kubernetes.io/part-of": "argocd",
  1168  					},
  1169  				},
  1170  				Data: map[string][]byte{
  1171  					"admin.password":   nil,
  1172  					"server.secretkey": nil,
  1173  				},
  1174  			},
  1175  			&corev1.Secret{
  1176  				ObjectMeta: metav1.ObjectMeta{
  1177  					Name:      externalServerTLSSecretName,
  1178  					Namespace: "default",
  1179  				},
  1180  				Data: map[string][]byte{
  1181  					"tls.crt": []byte(testutil.MustLoadFileToString("../../test/fixture/certs/argocd-test-server.crt")),
  1182  					"tls.key": []byte(testutil.MustLoadFileToString("../../test/fixture/certs/argocd-test-server.key")),
  1183  				},
  1184  			},
  1185  		)
  1186  		settingsManager := NewSettingsManager(t.Context(), kubeClient, "default")
  1187  		settings, err := settingsManager.GetSettings()
  1188  		require.NoError(t, err)
  1189  		assert.True(t, settings.CertificateIsExternal)
  1190  		assert.NotNil(t, settings.Certificate)
  1191  		assert.Contains(t, getCNFromCertificate(settings.Certificate), "localhost")
  1192  	})
  1193  
  1194  	t.Run("Valid external TLS secret overrides argocd-secret", func(t *testing.T) {
  1195  		kubeClient := fake.NewClientset(
  1196  			&corev1.ConfigMap{
  1197  				ObjectMeta: metav1.ObjectMeta{
  1198  					Name:      common.ArgoCDConfigMapName,
  1199  					Namespace: "default",
  1200  					Labels: map[string]string{
  1201  						"app.kubernetes.io/part-of": "argocd",
  1202  					},
  1203  				},
  1204  				Data: map[string]string{
  1205  					"oidc.config": "\n  name: Okta\n  clientSecret: test-secret\r\n \n  clientID: aaaabbbbccccddddeee\n",
  1206  				},
  1207  			},
  1208  			&corev1.Secret{
  1209  				ObjectMeta: metav1.ObjectMeta{
  1210  					Name:      common.ArgoCDSecretName,
  1211  					Namespace: "default",
  1212  					Labels: map[string]string{
  1213  						"app.kubernetes.io/part-of": "argocd",
  1214  					},
  1215  				},
  1216  				Data: map[string][]byte{
  1217  					"admin.password":   nil,
  1218  					"server.secretkey": nil,
  1219  					"tls.crt":          []byte(testutil.MustLoadFileToString("../../test/fixture/certs/argocd-e2e-server.crt")),
  1220  					"tls.key":          []byte(testutil.MustLoadFileToString("../../test/fixture/certs/argocd-e2e-server.key")),
  1221  				},
  1222  			},
  1223  			&corev1.Secret{
  1224  				ObjectMeta: metav1.ObjectMeta{
  1225  					Name:      externalServerTLSSecretName,
  1226  					Namespace: "default",
  1227  				},
  1228  				Data: map[string][]byte{
  1229  					"tls.crt": []byte(testutil.MustLoadFileToString("../../test/fixture/certs/argocd-test-server.crt")),
  1230  					"tls.key": []byte(testutil.MustLoadFileToString("../../test/fixture/certs/argocd-test-server.key")),
  1231  				},
  1232  			},
  1233  		)
  1234  		settingsManager := NewSettingsManager(t.Context(), kubeClient, "default")
  1235  		settings, err := settingsManager.GetSettings()
  1236  		require.NoError(t, err)
  1237  		assert.True(t, settings.CertificateIsExternal)
  1238  		assert.NotNil(t, settings.Certificate)
  1239  		assert.Contains(t, getCNFromCertificate(settings.Certificate), "localhost")
  1240  	})
  1241  	t.Run("Invalid external TLS secret", func(t *testing.T) {
  1242  		kubeClient := fake.NewClientset(
  1243  			&corev1.ConfigMap{
  1244  				ObjectMeta: metav1.ObjectMeta{
  1245  					Name:      common.ArgoCDConfigMapName,
  1246  					Namespace: "default",
  1247  					Labels: map[string]string{
  1248  						"app.kubernetes.io/part-of": "argocd",
  1249  					},
  1250  				},
  1251  				Data: map[string]string{
  1252  					"oidc.config": "\n  name: Okta\n  clientSecret: test-secret\r\n \n  clientID: aaaabbbbccccddddeee\n",
  1253  				},
  1254  			},
  1255  			&corev1.Secret{
  1256  				ObjectMeta: metav1.ObjectMeta{
  1257  					Name:      common.ArgoCDSecretName,
  1258  					Namespace: "default",
  1259  					Labels: map[string]string{
  1260  						"app.kubernetes.io/part-of": "argocd",
  1261  					},
  1262  				},
  1263  				Data: map[string][]byte{
  1264  					"admin.password":   nil,
  1265  					"server.secretkey": nil,
  1266  				},
  1267  			},
  1268  			&corev1.Secret{
  1269  				ObjectMeta: metav1.ObjectMeta{
  1270  					Name:      externalServerTLSSecretName,
  1271  					Namespace: "default",
  1272  				},
  1273  				Data: map[string][]byte{
  1274  					"tls.crt": []byte(""),
  1275  					"tls.key": []byte(""),
  1276  				},
  1277  			},
  1278  		)
  1279  		settingsManager := NewSettingsManager(t.Context(), kubeClient, "default")
  1280  		settings, err := settingsManager.GetSettings()
  1281  		require.ErrorContains(t, err, "failed to find any PEM data in certificate input")
  1282  		assert.NotNil(t, settings)
  1283  	})
  1284  	t.Run("Does not parse TLS cert key pair on cache hit", func(t *testing.T) {
  1285  		cm := &corev1.ConfigMap{
  1286  			ObjectMeta: metav1.ObjectMeta{
  1287  				Name:      common.ArgoCDConfigMapName,
  1288  				Namespace: "default",
  1289  				Labels: map[string]string{
  1290  					"app.kubernetes.io/part-of": "argocd",
  1291  				},
  1292  			},
  1293  		}
  1294  		secret := &corev1.Secret{
  1295  			ObjectMeta: metav1.ObjectMeta{
  1296  				Name:            common.ArgoCDSecretName,
  1297  				Namespace:       "default",
  1298  				ResourceVersion: "1",
  1299  				Labels: map[string]string{
  1300  					"app.kubernetes.io/part-of": "argocd",
  1301  				},
  1302  			},
  1303  			Data: map[string][]byte{
  1304  				"server.secretkey": nil,
  1305  			},
  1306  		}
  1307  		tlsSecret := &corev1.Secret{
  1308  			ObjectMeta: metav1.ObjectMeta{
  1309  				Name:            externalServerTLSSecretName,
  1310  				Namespace:       "default",
  1311  				ResourceVersion: "1",
  1312  			},
  1313  			Data: map[string][]byte{
  1314  				"tls.crt": []byte(testutil.MustLoadFileToString("../../test/fixture/certs/argocd-test-server.crt")),
  1315  				"tls.key": []byte(testutil.MustLoadFileToString("../../test/fixture/certs/argocd-test-server.key")),
  1316  			},
  1317  		}
  1318  
  1319  		kubeClient := fake.NewClientset(cm, secret, tlsSecret)
  1320  		callCount := 0
  1321  		settingsManager := NewSettingsManager(context.Background(), kubeClient, "default", func(mgr *SettingsManager) {
  1322  			mgr.tlsCertParser = func(certpem []byte, keypem []byte) (tls.Certificate, error) {
  1323  				callCount++
  1324  
  1325  				return tls.X509KeyPair(certpem, keypem)
  1326  			}
  1327  		})
  1328  
  1329  		// should not be called by initialization
  1330  		assert.Equal(t, 0, callCount)
  1331  
  1332  		// should be called by first call to GetSettings
  1333  		_, err := settingsManager.GetSettings()
  1334  		require.NoError(t, err)
  1335  		assert.Equal(t, 1, callCount)
  1336  
  1337  		// should not be called by subsequent call to GetSettings
  1338  		_, err = settingsManager.GetSettings()
  1339  		require.NoError(t, err)
  1340  		assert.Equal(t, 1, callCount)
  1341  	})
  1342  	t.Run("Parses TLS cert key pair when TLS secret update causes cache miss", func(t *testing.T) {
  1343  		cm := &corev1.ConfigMap{
  1344  			ObjectMeta: metav1.ObjectMeta{
  1345  				Name:      common.ArgoCDConfigMapName,
  1346  				Namespace: "default",
  1347  				Labels: map[string]string{
  1348  					"app.kubernetes.io/part-of": "argocd",
  1349  				},
  1350  			},
  1351  		}
  1352  		secret := &corev1.Secret{
  1353  			ObjectMeta: metav1.ObjectMeta{
  1354  				Name:            common.ArgoCDSecretName,
  1355  				Namespace:       "default",
  1356  				ResourceVersion: "1",
  1357  				Labels: map[string]string{
  1358  					"app.kubernetes.io/part-of": "argocd",
  1359  				},
  1360  			},
  1361  			Data: map[string][]byte{
  1362  				"server.secretkey": nil,
  1363  			},
  1364  		}
  1365  		tlsSecret := &corev1.Secret{
  1366  			ObjectMeta: metav1.ObjectMeta{
  1367  				Name:            externalServerTLSSecretName,
  1368  				Namespace:       "default",
  1369  				ResourceVersion: "1",
  1370  			},
  1371  			Data: map[string][]byte{
  1372  				"tls.crt": []byte(testutil.MustLoadFileToString("../../test/fixture/certs/argocd-test-server.crt")),
  1373  				"tls.key": []byte(testutil.MustLoadFileToString("../../test/fixture/certs/argocd-test-server.key")),
  1374  			},
  1375  		}
  1376  
  1377  		kubeClient := fake.NewClientset(cm, secret, tlsSecret)
  1378  		callCount := 0
  1379  		settingsManager := NewSettingsManager(context.Background(), kubeClient, "default", func(mgr *SettingsManager) {
  1380  			mgr.tlsCertParser = func(certpem []byte, keypem []byte) (tls.Certificate, error) {
  1381  				callCount++
  1382  
  1383  				return tls.X509KeyPair(certpem, keypem)
  1384  			}
  1385  		})
  1386  
  1387  		// should be called by first call to GetSettings
  1388  		settings, err := settingsManager.GetSettings()
  1389  		require.NoError(t, err)
  1390  		assert.Equal(t, 1, callCount)
  1391  		assert.NotNil(t, settings.Certificate)
  1392  		assert.True(t, settings.CertificateIsExternal)
  1393  		assert.Equal(t, "localhost", getCNFromCertificate(settings.Certificate))
  1394  
  1395  		// update secret
  1396  		tlsSecret.SetResourceVersion("2")
  1397  		_, err = kubeClient.CoreV1().Secrets("default").Update(t.Context(), tlsSecret, metav1.UpdateOptions{})
  1398  		require.NoError(t, err)
  1399  
  1400  		// allow time for the udpate to resolve to avoid timing issues below
  1401  		time.Sleep(250 * time.Millisecond)
  1402  
  1403  		// should be called again after secret update resolves
  1404  		settings, err = settingsManager.GetSettings()
  1405  		require.NoError(t, err)
  1406  		assert.Equal(t, 2, callCount)
  1407  		assert.NotNil(t, settings.Certificate)
  1408  		assert.True(t, settings.CertificateIsExternal)
  1409  		assert.Equal(t, "localhost", getCNFromCertificate(settings.Certificate))
  1410  	})
  1411  	t.Run("Overrides cached internal TLS cert when external TLS secret added", func(t *testing.T) {
  1412  		kubeClient := fake.NewClientset(
  1413  			&corev1.ConfigMap{
  1414  				ObjectMeta: metav1.ObjectMeta{
  1415  					Name:      common.ArgoCDConfigMapName,
  1416  					Namespace: "default",
  1417  					Labels: map[string]string{
  1418  						"app.kubernetes.io/part-of": "argocd",
  1419  					},
  1420  				},
  1421  			},
  1422  			&corev1.Secret{
  1423  				ObjectMeta: metav1.ObjectMeta{
  1424  					Name:            common.ArgoCDSecretName,
  1425  					Namespace:       "default",
  1426  					ResourceVersion: "1",
  1427  					Labels: map[string]string{
  1428  						"app.kubernetes.io/part-of": "argocd",
  1429  					},
  1430  				},
  1431  				Data: map[string][]byte{
  1432  					"server.secretkey": nil,
  1433  					"tls.crt":          []byte(testutil.MustLoadFileToString("../../test/fixture/certs/argocd-e2e-server.crt")),
  1434  					"tls.key":          []byte(testutil.MustLoadFileToString("../../test/fixture/certs/argocd-e2e-server.key")),
  1435  				},
  1436  			},
  1437  		)
  1438  		settingsManager := NewSettingsManager(t.Context(), kubeClient, "default")
  1439  		settings, err := settingsManager.GetSettings()
  1440  		require.NoError(t, err)
  1441  		// should have internal cert at this point
  1442  		assert.NotNil(t, settings.Certificate)
  1443  		assert.False(t, settings.CertificateIsExternal)
  1444  		assert.Equal(t, "Argo CD E2E", getCNFromCertificate(settings.Certificate))
  1445  
  1446  		externalTLSSecret := &corev1.Secret{
  1447  			ObjectMeta: metav1.ObjectMeta{
  1448  				Name:            externalServerTLSSecretName,
  1449  				Namespace:       "default",
  1450  				ResourceVersion: "1",
  1451  			},
  1452  			Data: map[string][]byte{
  1453  				"tls.crt": []byte(testutil.MustLoadFileToString("../../test/fixture/certs/argocd-test-server.crt")),
  1454  				"tls.key": []byte(testutil.MustLoadFileToString("../../test/fixture/certs/argocd-test-server.key")),
  1455  			},
  1456  		}
  1457  		_, err = kubeClient.CoreV1().Secrets("default").Create(t.Context(), externalTLSSecret, metav1.CreateOptions{})
  1458  		require.NoError(t, err)
  1459  
  1460  		// allow time for the create to resolve to avoid timing issues below
  1461  		time.Sleep(250 * time.Millisecond)
  1462  
  1463  		settings, err = settingsManager.GetSettings()
  1464  		require.NoError(t, err)
  1465  		// should now have an external cert
  1466  		assert.NotNil(t, settings.Certificate)
  1467  		assert.True(t, settings.CertificateIsExternal)
  1468  		assert.Equal(t, "localhost", getCNFromCertificate(settings.Certificate))
  1469  	})
  1470  	t.Run("Falls back to internal TLS cert when external TLS secret deleted", func(t *testing.T) {
  1471  		kubeClient := fake.NewClientset(
  1472  			&corev1.ConfigMap{
  1473  				ObjectMeta: metav1.ObjectMeta{
  1474  					Name:      common.ArgoCDConfigMapName,
  1475  					Namespace: "default",
  1476  					Labels: map[string]string{
  1477  						"app.kubernetes.io/part-of": "argocd",
  1478  					},
  1479  				},
  1480  			},
  1481  			&corev1.Secret{
  1482  				ObjectMeta: metav1.ObjectMeta{
  1483  					Name:            common.ArgoCDSecretName,
  1484  					Namespace:       "default",
  1485  					ResourceVersion: "1",
  1486  					Labels: map[string]string{
  1487  						"app.kubernetes.io/part-of": "argocd",
  1488  					},
  1489  				},
  1490  				Data: map[string][]byte{
  1491  					"server.secretkey": nil,
  1492  					"tls.crt":          []byte(testutil.MustLoadFileToString("../../test/fixture/certs/argocd-e2e-server.crt")),
  1493  					"tls.key":          []byte(testutil.MustLoadFileToString("../../test/fixture/certs/argocd-e2e-server.key")),
  1494  				},
  1495  			},
  1496  			&corev1.Secret{
  1497  				ObjectMeta: metav1.ObjectMeta{
  1498  					Name:            externalServerTLSSecretName,
  1499  					Namespace:       "default",
  1500  					ResourceVersion: "1",
  1501  				},
  1502  				Data: map[string][]byte{
  1503  					"tls.crt": []byte(testutil.MustLoadFileToString("../../test/fixture/certs/argocd-test-server.crt")),
  1504  					"tls.key": []byte(testutil.MustLoadFileToString("../../test/fixture/certs/argocd-test-server.key")),
  1505  				},
  1506  			},
  1507  		)
  1508  		settingsManager := NewSettingsManager(t.Context(), kubeClient, "default")
  1509  		settings, err := settingsManager.GetSettings()
  1510  		require.NoError(t, err)
  1511  		// should have external cert at this point
  1512  		assert.NotNil(t, settings.Certificate)
  1513  		assert.True(t, settings.CertificateIsExternal)
  1514  		assert.Equal(t, "localhost", getCNFromCertificate(settings.Certificate))
  1515  
  1516  		err = kubeClient.CoreV1().Secrets("default").Delete(t.Context(), externalServerTLSSecretName, metav1.DeleteOptions{})
  1517  		require.NoError(t, err)
  1518  
  1519  		// allow time for the delete to resolve to avoid timing issues below
  1520  		time.Sleep(250 * time.Millisecond)
  1521  
  1522  		settings, err = settingsManager.GetSettings()
  1523  		require.NoError(t, err)
  1524  		// should now have an internal cert
  1525  		assert.NotNil(t, settings.Certificate)
  1526  		assert.False(t, settings.CertificateIsExternal)
  1527  		assert.Equal(t, "Argo CD E2E", getCNFromCertificate(settings.Certificate))
  1528  	})
  1529  	t.Run("No external TLS secret", func(t *testing.T) {
  1530  		kubeClient := fake.NewClientset(
  1531  			&corev1.ConfigMap{
  1532  				ObjectMeta: metav1.ObjectMeta{
  1533  					Name:      common.ArgoCDConfigMapName,
  1534  					Namespace: "default",
  1535  					Labels: map[string]string{
  1536  						"app.kubernetes.io/part-of": "argocd",
  1537  					},
  1538  				},
  1539  				Data: map[string]string{
  1540  					"oidc.config": "\n  name: Okta\n  clientSecret: test-secret\r\n \n  clientID: aaaabbbbccccddddeee\n",
  1541  				},
  1542  			},
  1543  			&corev1.Secret{
  1544  				ObjectMeta: metav1.ObjectMeta{
  1545  					Name:      common.ArgoCDSecretName,
  1546  					Namespace: "default",
  1547  					Labels: map[string]string{
  1548  						"app.kubernetes.io/part-of": "argocd",
  1549  					},
  1550  				},
  1551  				Data: map[string][]byte{
  1552  					"admin.password":   nil,
  1553  					"server.secretkey": nil,
  1554  					"tls.crt":          []byte(testutil.MustLoadFileToString("../../test/fixture/certs/argocd-e2e-server.crt")),
  1555  					"tls.key":          []byte(testutil.MustLoadFileToString("../../test/fixture/certs/argocd-e2e-server.key")),
  1556  				},
  1557  			},
  1558  		)
  1559  		settingsManager := NewSettingsManager(t.Context(), kubeClient, "default")
  1560  		settings, err := settingsManager.GetSettings()
  1561  		require.NoError(t, err)
  1562  		assert.False(t, settings.CertificateIsExternal)
  1563  		assert.NotNil(t, settings.Certificate)
  1564  		assert.Contains(t, getCNFromCertificate(settings.Certificate), "Argo CD E2E")
  1565  	})
  1566  }
  1567  
  1568  func TestDownloadArgoCDBinaryUrls(t *testing.T) {
  1569  	_, settingsManager := fixtures(map[string]string{
  1570  		"help.download.darwin-amd64": "some-url",
  1571  	})
  1572  	argoCDCM, err := settingsManager.getConfigMap()
  1573  	require.NoError(t, err)
  1574  	assert.Equal(t, "some-url", argoCDCM.Data["help.download.darwin-amd64"])
  1575  
  1576  	_, settingsManager = fixtures(map[string]string{
  1577  		"help.download.linux-s390x": "some-url",
  1578  	})
  1579  	argoCDCM, err = settingsManager.getConfigMap()
  1580  	require.NoError(t, err)
  1581  	assert.Equal(t, "some-url", argoCDCM.Data["help.download.linux-s390x"])
  1582  
  1583  	_, settingsManager = fixtures(map[string]string{
  1584  		"help.download.unsupported": "some-url",
  1585  	})
  1586  	argoCDCM, err = settingsManager.getConfigMap()
  1587  	require.NoError(t, err)
  1588  	assert.Equal(t, "some-url", argoCDCM.Data["help.download.unsupported"])
  1589  }
  1590  
  1591  func TestSecretKeyRef(t *testing.T) {
  1592  	data := map[string]string{
  1593  		"oidc.config": `name: Okta
  1594  issuer: $ext:issuerSecret
  1595  clientID: aaaabbbbccccddddeee
  1596  clientSecret: $ext:clientSecret
  1597  # Optional set of OIDC scopes to request. If omitted, defaults to: ["openid", "profile", "email", "groups"]
  1598  requestedScopes: ["openid", "profile", "email"]
  1599  # Optional set of OIDC claims to request on the ID token.
  1600  requestedIDTokenClaims: {"groups": {"essential": true}}`,
  1601  	}
  1602  	cm := &corev1.ConfigMap{
  1603  		ObjectMeta: metav1.ObjectMeta{
  1604  			Name:      common.ArgoCDConfigMapName,
  1605  			Namespace: "default",
  1606  			Labels: map[string]string{
  1607  				"app.kubernetes.io/part-of": "argocd",
  1608  			},
  1609  		},
  1610  		Data: data,
  1611  	}
  1612  	argocdSecret := &corev1.Secret{
  1613  		ObjectMeta: metav1.ObjectMeta{
  1614  			Name:      common.ArgoCDSecretName,
  1615  			Namespace: "default",
  1616  		},
  1617  		Data: map[string][]byte{
  1618  			"admin.password":        nil,
  1619  			"server.secretkey":      nil,
  1620  			"webhook.github.secret": []byte("$ext:webhook.github.secret"),
  1621  		},
  1622  	}
  1623  	secret := &corev1.Secret{
  1624  		ObjectMeta: metav1.ObjectMeta{
  1625  			Name:      "ext",
  1626  			Namespace: "default",
  1627  			Labels: map[string]string{
  1628  				"app.kubernetes.io/part-of": "argocd",
  1629  			},
  1630  		},
  1631  		Data: map[string][]byte{
  1632  			"issuerSecret":          []byte("https://dev-123456.oktapreview.com"),
  1633  			"clientSecret":          []byte("deadbeef"),
  1634  			"webhook.github.secret": []byte("mywebhooksecret"),
  1635  		},
  1636  	}
  1637  	kubeClient := fake.NewClientset(cm, secret, argocdSecret)
  1638  	settingsManager := NewSettingsManager(t.Context(), kubeClient, "default")
  1639  
  1640  	settings, err := settingsManager.GetSettings()
  1641  	require.NoError(t, err)
  1642  	assert.Equal(t, "mywebhooksecret", settings.GetWebhookGitHubSecret())
  1643  
  1644  	oidcConfig := settings.OIDCConfig()
  1645  	assert.Equal(t, "https://dev-123456.oktapreview.com", oidcConfig.Issuer)
  1646  	assert.Equal(t, "deadbeef", oidcConfig.ClientSecret)
  1647  }
  1648  
  1649  func TestGetEnableManifestGeneration(t *testing.T) {
  1650  	testCases := []struct {
  1651  		name    string
  1652  		enabled bool
  1653  		data    map[string]string
  1654  		source  string
  1655  	}{{
  1656  		name:    "default",
  1657  		enabled: true,
  1658  		data:    map[string]string{},
  1659  		source:  string(v1alpha1.ApplicationSourceTypeKustomize),
  1660  	}, {
  1661  		name:    "disabled",
  1662  		enabled: false,
  1663  		data:    map[string]string{"kustomize.enable": `false`},
  1664  		source:  string(v1alpha1.ApplicationSourceTypeKustomize),
  1665  	}, {
  1666  		name:    "enabled",
  1667  		enabled: true,
  1668  		data:    map[string]string{"kustomize.enable": `true`},
  1669  		source:  string(v1alpha1.ApplicationSourceTypeKustomize),
  1670  	}}
  1671  	for i := range testCases {
  1672  		tc := testCases[i]
  1673  		t.Run(tc.name, func(t *testing.T) {
  1674  			cm := &corev1.ConfigMap{
  1675  				ObjectMeta: metav1.ObjectMeta{
  1676  					Name:      common.ArgoCDConfigMapName,
  1677  					Namespace: "default",
  1678  					Labels: map[string]string{
  1679  						"app.kubernetes.io/part-of": "argocd",
  1680  					},
  1681  				},
  1682  				Data: tc.data,
  1683  			}
  1684  			argocdSecret := &corev1.Secret{
  1685  				ObjectMeta: metav1.ObjectMeta{
  1686  					Name:      common.ArgoCDSecretName,
  1687  					Namespace: "default",
  1688  				},
  1689  				Data: map[string][]byte{
  1690  					"admin.password":   nil,
  1691  					"server.secretkey": nil,
  1692  				},
  1693  			}
  1694  
  1695  			kubeClient := fake.NewClientset(cm, argocdSecret)
  1696  			settingsManager := NewSettingsManager(t.Context(), kubeClient, "default")
  1697  
  1698  			enableManifestGeneration, err := settingsManager.GetEnabledSourceTypes()
  1699  			require.NoError(t, err)
  1700  
  1701  			assert.Equal(t, enableManifestGeneration[tc.source], tc.enabled)
  1702  		})
  1703  	}
  1704  }
  1705  
  1706  func TestGetHelmSettings(t *testing.T) {
  1707  	testCases := []struct {
  1708  		name     string
  1709  		data     map[string]string
  1710  		expected []string
  1711  	}{{
  1712  		name:     "Default",
  1713  		data:     map[string]string{},
  1714  		expected: []string{"http", "https"},
  1715  	}, {
  1716  		name: "Configured Not Empty",
  1717  		data: map[string]string{
  1718  			"helm.valuesFileSchemes": "s3, git",
  1719  		},
  1720  		expected: []string{"s3", "git"},
  1721  	}, {
  1722  		name: "Configured Empty",
  1723  		data: map[string]string{
  1724  			"helm.valuesFileSchemes": "",
  1725  		},
  1726  		expected: nil,
  1727  	}}
  1728  
  1729  	for i := range testCases {
  1730  		tc := testCases[i]
  1731  		t.Run(tc.name, func(t *testing.T) {
  1732  			cm := &corev1.ConfigMap{
  1733  				ObjectMeta: metav1.ObjectMeta{
  1734  					Name:      common.ArgoCDConfigMapName,
  1735  					Namespace: "default",
  1736  					Labels: map[string]string{
  1737  						"app.kubernetes.io/part-of": "argocd",
  1738  					},
  1739  				},
  1740  				Data: tc.data,
  1741  			}
  1742  			argocdSecret := &corev1.Secret{
  1743  				ObjectMeta: metav1.ObjectMeta{
  1744  					Name:      common.ArgoCDSecretName,
  1745  					Namespace: "default",
  1746  				},
  1747  				Data: map[string][]byte{
  1748  					"admin.password":   nil,
  1749  					"server.secretkey": nil,
  1750  				},
  1751  			}
  1752  			secret := &corev1.Secret{
  1753  				ObjectMeta: metav1.ObjectMeta{
  1754  					Name:      "acme",
  1755  					Namespace: "default",
  1756  					Labels: map[string]string{
  1757  						"app.kubernetes.io/part-of": "argocd",
  1758  					},
  1759  				},
  1760  				Data: map[string][]byte{
  1761  					"clientSecret": []byte("deadbeef"),
  1762  				},
  1763  			}
  1764  			kubeClient := fake.NewClientset(cm, secret, argocdSecret)
  1765  			settingsManager := NewSettingsManager(t.Context(), kubeClient, "default")
  1766  
  1767  			helmSettings, err := settingsManager.GetHelmSettings()
  1768  			require.NoError(t, err)
  1769  
  1770  			assert.ElementsMatch(t, tc.expected, helmSettings.ValuesFileSchemes)
  1771  		})
  1772  	}
  1773  }
  1774  
  1775  func TestArgoCDSettings_OIDCTLSConfig_OIDCTLSInsecureSkipVerify(t *testing.T) {
  1776  	certParsed, err := tls.X509KeyPair(test.Cert, test.PrivateKey)
  1777  	require.NoError(t, err)
  1778  
  1779  	testCases := []struct {
  1780  		name               string
  1781  		settings           *ArgoCDSettings
  1782  		expectNilTLSConfig bool
  1783  	}{
  1784  		{
  1785  			name: "OIDC configured, no root CA",
  1786  			settings: &ArgoCDSettings{OIDCConfigRAW: `name: Test
  1787  issuer: aaa
  1788  clientID: xxx
  1789  clientSecret: yyy
  1790  requestedScopes: ["oidc"]`},
  1791  		},
  1792  		{
  1793  			name: "OIDC configured, valid root CA",
  1794  			settings: &ArgoCDSettings{OIDCConfigRAW: fmt.Sprintf(`
  1795  name: Test
  1796  issuer: aaa
  1797  clientID: xxx
  1798  clientSecret: yyy
  1799  requestedScopes: ["oidc"]
  1800  rootCA: |
  1801    %s
  1802  `, strings.ReplaceAll(string(test.Cert), "\n", "\n  "))},
  1803  		},
  1804  		{
  1805  			name: "OIDC configured, invalid root CA",
  1806  			settings: &ArgoCDSettings{OIDCConfigRAW: `name: Test
  1807  issuer: aaa
  1808  clientID: xxx
  1809  clientSecret: yyy
  1810  requestedScopes: ["oidc"]
  1811  rootCA: "invalid"`},
  1812  		},
  1813  		{
  1814  			name:               "OIDC not configured, no cert configured",
  1815  			settings:           &ArgoCDSettings{},
  1816  			expectNilTLSConfig: true,
  1817  		},
  1818  		{
  1819  			name:     "OIDC not configured, cert configured",
  1820  			settings: &ArgoCDSettings{Certificate: &certParsed},
  1821  		},
  1822  	}
  1823  
  1824  	for _, testCase := range testCases {
  1825  		testCase := testCase
  1826  
  1827  		t.Run(testCase.name, func(t *testing.T) {
  1828  			if testCase.expectNilTLSConfig {
  1829  				assert.Nil(t, testCase.settings.OIDCTLSConfig())
  1830  			} else {
  1831  				assert.False(t, testCase.settings.OIDCTLSConfig().InsecureSkipVerify)
  1832  
  1833  				testCase.settings.OIDCTLSInsecureSkipVerify = true
  1834  
  1835  				assert.True(t, testCase.settings.OIDCTLSConfig().InsecureSkipVerify)
  1836  			}
  1837  		})
  1838  	}
  1839  }
  1840  
  1841  func Test_OAuth2AllowedAudiences(t *testing.T) {
  1842  	t.Parallel()
  1843  
  1844  	testCases := []struct {
  1845  		name     string
  1846  		settings *ArgoCDSettings
  1847  		expected []string
  1848  	}{
  1849  		{
  1850  			name:     "Empty",
  1851  			settings: &ArgoCDSettings{},
  1852  			expected: []string{},
  1853  		},
  1854  		{
  1855  			name: "OIDC configured, no audiences specified, clientID used",
  1856  			settings: &ArgoCDSettings{OIDCConfigRAW: `name: Test
  1857  issuer: aaa
  1858  clientID: xxx
  1859  clientSecret: yyy
  1860  requestedScopes: ["oidc"]`},
  1861  			expected: []string{"xxx"},
  1862  		},
  1863  		{
  1864  			name: "OIDC configured, no audiences specified, clientID and cliClientID used",
  1865  			settings: &ArgoCDSettings{OIDCConfigRAW: `name: Test
  1866  issuer: aaa
  1867  clientID: xxx
  1868  cliClientID: cli-xxx
  1869  clientSecret: yyy
  1870  requestedScopes: ["oidc"]`},
  1871  			expected: []string{"xxx", "cli-xxx"},
  1872  		},
  1873  		{
  1874  			name: "OIDC configured, audiences specified",
  1875  			settings: &ArgoCDSettings{OIDCConfigRAW: `name: Test
  1876  issuer: aaa
  1877  clientID: xxx
  1878  clientSecret: yyy
  1879  requestedScopes: ["oidc"]
  1880  allowedAudiences: ["aud1", "aud2"]`},
  1881  			expected: []string{"aud1", "aud2"},
  1882  		},
  1883  		{
  1884  			name: "Dex configured",
  1885  			settings: &ArgoCDSettings{DexConfig: `connectors:
  1886    - type: github
  1887      id: github
  1888      name: GitHub
  1889      config:
  1890        clientID: aabbccddeeff00112233
  1891        clientSecret: $dex.github.clientSecret
  1892        orgs:
  1893        - name: your-github-org
  1894  `},
  1895  			expected: []string{common.ArgoCDClientAppID, common.ArgoCDCLIClientAppID},
  1896  		},
  1897  	}
  1898  
  1899  	for _, tc := range testCases {
  1900  		tcc := tc
  1901  		t.Run(tcc.name, func(t *testing.T) {
  1902  			t.Parallel()
  1903  			assert.ElementsMatch(t, tcc.expected, tcc.settings.OAuth2AllowedAudiences())
  1904  		})
  1905  	}
  1906  }
  1907  
  1908  func TestReplaceStringSecret(t *testing.T) {
  1909  	secretValues := map[string]string{"my-secret-key": "my-secret-value"}
  1910  	result := ReplaceStringSecret("$my-secret-key", secretValues)
  1911  	assert.Equal(t, "my-secret-value", result)
  1912  
  1913  	result = ReplaceStringSecret("$invalid-secret-key", secretValues)
  1914  	assert.Equal(t, "$invalid-secret-key", result)
  1915  
  1916  	result = ReplaceStringSecret("", secretValues)
  1917  	assert.Empty(t, result)
  1918  
  1919  	result = ReplaceStringSecret("my-value", secretValues)
  1920  	assert.Equal(t, "my-value", result)
  1921  }
  1922  
  1923  func TestRedirectURLForRequest(t *testing.T) {
  1924  	generateRequest := func(url string) *http.Request {
  1925  		r, err := http.NewRequest(http.MethodPost, url, http.NoBody)
  1926  		require.NoError(t, err)
  1927  		return r
  1928  	}
  1929  
  1930  	testCases := []struct {
  1931  		Name        string
  1932  		Settings    *ArgoCDSettings
  1933  		Request     *http.Request
  1934  		ExpectedURL string
  1935  		ExpectError bool
  1936  	}{
  1937  		{
  1938  			Name: "Single URL",
  1939  			Settings: &ArgoCDSettings{
  1940  				URL: "https://example.org",
  1941  			},
  1942  			Request:     generateRequest("https://example.org/login"),
  1943  			ExpectedURL: "https://example.org/auth/callback",
  1944  			ExpectError: false,
  1945  		},
  1946  		{
  1947  			Name: "Request does not match configured URL.",
  1948  			Settings: &ArgoCDSettings{
  1949  				URL: "https://otherhost.org",
  1950  			},
  1951  			Request:     generateRequest("https://example.org/login"),
  1952  			ExpectedURL: "https://otherhost.org/auth/callback",
  1953  			ExpectError: false,
  1954  		},
  1955  		{
  1956  			Name: "Cannot parse URL.",
  1957  			Settings: &ArgoCDSettings{
  1958  				URL: ":httpsotherhostorg",
  1959  			},
  1960  			Request:     generateRequest("https://example.org/login"),
  1961  			ExpectedURL: "",
  1962  			ExpectError: true,
  1963  		},
  1964  		{
  1965  			Name: "Match extended URL in settings.URL.",
  1966  			Settings: &ArgoCDSettings{
  1967  				URL:            "https://otherhost.org",
  1968  				AdditionalURLs: []string{"https://anotherhost.org"},
  1969  			},
  1970  			Request:     generateRequest("https://anotherhost.org/login"),
  1971  			ExpectedURL: "https://anotherhost.org/auth/callback",
  1972  			ExpectError: false,
  1973  		},
  1974  	}
  1975  
  1976  	for _, tc := range testCases {
  1977  		t.Run(tc.Name, func(t *testing.T) {
  1978  			result, err := tc.Settings.RedirectURLForRequest(tc.Request)
  1979  			assert.Equal(t, tc.ExpectedURL, result)
  1980  			if tc.ExpectError {
  1981  				assert.Error(t, err)
  1982  			} else {
  1983  				assert.NoError(t, err)
  1984  			}
  1985  		})
  1986  	}
  1987  }
  1988  
  1989  func TestRedirectAdditionalURLs(t *testing.T) {
  1990  	testCases := []struct {
  1991  		Name           string
  1992  		Settings       *ArgoCDSettings
  1993  		ExpectedResult []string
  1994  		ExpectedError  bool
  1995  	}{
  1996  		{
  1997  			Name: "Good case with two AdditionalURLs",
  1998  			Settings: &ArgoCDSettings{
  1999  				URL:            "https://example.org",
  2000  				AdditionalURLs: []string{"https://anotherhost.org", "https://yetanother.org"},
  2001  			},
  2002  			ExpectedResult: []string{
  2003  				"https://anotherhost.org/auth/callback",
  2004  				"https://yetanother.org/auth/callback",
  2005  			},
  2006  			ExpectedError: false,
  2007  		},
  2008  		{
  2009  			Name: "Bad URL causes error",
  2010  			Settings: &ArgoCDSettings{
  2011  				URL:            "https://example.org",
  2012  				AdditionalURLs: []string{":httpsotherhostorg"},
  2013  			},
  2014  			ExpectedResult: []string{},
  2015  			ExpectedError:  true,
  2016  		},
  2017  	}
  2018  
  2019  	for _, tc := range testCases {
  2020  		t.Run(tc.Name, func(t *testing.T) {
  2021  			result, err := tc.Settings.RedirectAdditionalURLs()
  2022  			if tc.ExpectedError {
  2023  				require.Error(t, err)
  2024  			} else {
  2025  				require.NoError(t, err)
  2026  			}
  2027  			require.Equal(t, tc.ExpectedResult, result)
  2028  		})
  2029  	}
  2030  }
  2031  
  2032  func TestUseAzureWorkloadIdentity(t *testing.T) {
  2033  	testCases := []struct {
  2034  		Name           string
  2035  		Settings       *ArgoCDSettings
  2036  		ExpectedResult bool
  2037  	}{
  2038  		{
  2039  			Name: "UseAzureWorkloadIdentity defined and set to true",
  2040  			Settings: &ArgoCDSettings{
  2041  				OIDCConfigRAW: "{ \"azure\": {\"useWorkloadIdentity\": true }}",
  2042  			},
  2043  			ExpectedResult: true,
  2044  		},
  2045  		{
  2046  			Name: "UseAzureWorkloadIdentity defined and set to false",
  2047  			Settings: &ArgoCDSettings{
  2048  				OIDCConfigRAW: "{ \"azure\": {\"useWorkloadIdentity\": false }}",
  2049  			},
  2050  			ExpectedResult: false,
  2051  		},
  2052  		{
  2053  			Name: "UseAzureWorkloadIdentity not defined, with azure key present",
  2054  			Settings: &ArgoCDSettings{
  2055  				OIDCConfigRAW: "{ \"azure\": {}}",
  2056  			},
  2057  			ExpectedResult: false,
  2058  		},
  2059  		{
  2060  			Name: "UseAzureWorkloadIdentity not defined",
  2061  			Settings: &ArgoCDSettings{
  2062  				OIDCConfigRAW: "{}",
  2063  			},
  2064  			ExpectedResult: false,
  2065  		},
  2066  		{
  2067  			Name:           "OIDC config isnot defined",
  2068  			Settings:       &ArgoCDSettings{},
  2069  			ExpectedResult: false,
  2070  		},
  2071  	}
  2072  
  2073  	for _, tc := range testCases {
  2074  		t.Run(tc.Name, func(t *testing.T) {
  2075  			result := tc.Settings.UseAzureWorkloadIdentity()
  2076  			require.Equal(t, tc.ExpectedResult, result)
  2077  		})
  2078  	}
  2079  }
  2080  
  2081  func TestIsImpersonationEnabled(t *testing.T) {
  2082  	// When there is no argocd-cm itself,
  2083  	// Then IsImpersonationEnabled() must return false (default value) and an error with appropriate error message.
  2084  	kubeClient := fake.NewClientset()
  2085  	settingsManager := NewSettingsManager(t.Context(), kubeClient, "default")
  2086  	featureFlag, err := settingsManager.IsImpersonationEnabled()
  2087  	require.False(t, featureFlag,
  2088  		"with no argocd-cm config map, IsImpersonationEnabled() must return return false (default value)")
  2089  	require.ErrorContains(t, err, "configmap \"argocd-cm\" not found",
  2090  		"with no argocd-cm config map, IsImpersonationEnabled() must return an error")
  2091  
  2092  	// When there is no impersonation feature flag present in the argocd-cm,
  2093  	// Then IsImpersonationEnabled() must return false (default value) and nil error.
  2094  	_, settingsManager = fixtures(map[string]string{})
  2095  	featureFlag, err = settingsManager.IsImpersonationEnabled()
  2096  	require.False(t, featureFlag,
  2097  		"with empty argocd-cm config map, IsImpersonationEnabled() must return false (default value)")
  2098  	require.NoError(t, err,
  2099  		"with empty argocd-cm config map, IsImpersonationEnabled() must not return any error")
  2100  
  2101  	// When user disables the feature explicitly,
  2102  	// Then IsImpersonationEnabled() must return false and nil error.
  2103  	_, settingsManager = fixtures(map[string]string{
  2104  		"application.sync.impersonation.enabled": "false",
  2105  	})
  2106  	featureFlag, err = settingsManager.IsImpersonationEnabled()
  2107  	require.False(t, featureFlag,
  2108  		"when user enables the flag in argocd-cm config map, IsImpersonationEnabled() must return user set value")
  2109  	require.NoError(t, err,
  2110  		"when user enables the flag in argocd-cm config map, IsImpersonationEnabled() must not return any error")
  2111  
  2112  	// When user enables the feature explicitly,
  2113  	// Then IsImpersonationEnabled() must return true and nil error.
  2114  	_, settingsManager = fixtures(map[string]string{
  2115  		"application.sync.impersonation.enabled": "true",
  2116  	})
  2117  	featureFlag, err = settingsManager.IsImpersonationEnabled()
  2118  	require.True(t, featureFlag,
  2119  		"when user enables the flag in argocd-cm config map, IsImpersonationEnabled() must return user set value")
  2120  	require.NoError(t, err,
  2121  		"when user enables the flag in argocd-cm config map, IsImpersonationEnabled() must not return any error")
  2122  }
  2123  
  2124  func TestSettingsManager_GetHideSecretAnnotations(t *testing.T) {
  2125  	tests := []struct {
  2126  		name   string
  2127  		input  string
  2128  		output map[string]bool
  2129  	}{
  2130  		{
  2131  			name:   "Empty input",
  2132  			input:  "",
  2133  			output: map[string]bool{},
  2134  		},
  2135  		{
  2136  			name:   "Comma separated data",
  2137  			input:  "example.com/token-secret.value,token,key",
  2138  			output: map[string]bool{"example.com/token-secret.value": true, "token": true, "key": true},
  2139  		},
  2140  		{
  2141  			name:   "Comma separated data with space",
  2142  			input:  "example.com/token-secret.value, token,    key",
  2143  			output: map[string]bool{"example.com/token-secret.value": true, "token": true, "key": true},
  2144  		},
  2145  	}
  2146  	for _, tt := range tests {
  2147  		t.Run(tt.name, func(t *testing.T) {
  2148  			_, settingsManager := fixtures(map[string]string{
  2149  				resourceSensitiveAnnotationsKey: tt.input,
  2150  			})
  2151  			keys := settingsManager.GetSensitiveAnnotations()
  2152  			assert.Len(t, keys, len(tt.output))
  2153  			assert.Equal(t, tt.output, keys)
  2154  		})
  2155  	}
  2156  }
  2157  
  2158  func TestSettingsManager_GetAllowedNodeLabels(t *testing.T) {
  2159  	tests := []struct {
  2160  		name   string
  2161  		input  string
  2162  		output []string
  2163  	}{
  2164  		{
  2165  			name:   "Empty input",
  2166  			input:  "",
  2167  			output: []string{},
  2168  		},
  2169  		{
  2170  			name:   "Comma separated data",
  2171  			input:  "example.com/label,label1,label2",
  2172  			output: []string{"example.com/label", "label1", "label2"},
  2173  		},
  2174  		{
  2175  			name:   "Comma separated data with space",
  2176  			input:  "example.com/label, label1,    label2",
  2177  			output: []string{"example.com/label", "label1", "label2"},
  2178  		},
  2179  		{
  2180  			name:   "Comma separated data with invalid label",
  2181  			input:  "example.com/label,_invalid,label1,label2",
  2182  			output: []string{"example.com/label", "label1", "label2"},
  2183  		},
  2184  	}
  2185  	for _, tt := range tests {
  2186  		t.Run(tt.name, func(t *testing.T) {
  2187  			_, settingsManager := fixtures(map[string]string{
  2188  				allowedNodeLabelsKey: tt.input,
  2189  			})
  2190  			keys := settingsManager.GetAllowedNodeLabels()
  2191  			assert.Len(t, keys, len(tt.output))
  2192  			assert.Equal(t, tt.output, keys)
  2193  		})
  2194  	}
  2195  }