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 }