From e36f87b1a9bb46b082668bd0ee5567e9d9f82302 Mon Sep 17 00:00:00 2001 From: wesleymccollam Date: Wed, 4 Jun 2025 17:00:18 -0400 Subject: [PATCH] CDI-514: Return support for Case-Insensitive keys --- internal/profiles/koanf.go | 39 +++++++++++++-- internal/profiles/validate_test.go | 10 ++++ .../testing/testutils_koanf/koanf_utils.go | 49 +++++++++++++++++++ 3 files changed, 94 insertions(+), 4 deletions(-) diff --git a/internal/profiles/koanf.go b/internal/profiles/koanf.go index 682c5fd7..4dddaddc 100644 --- a/internal/profiles/koanf.go +++ b/internal/profiles/koanf.go @@ -69,8 +69,11 @@ func KoanfValueFromOption(opt options.Option, pName string) (value string, ok bo ) // Case 1: Koanf Key is the ActiveProfile Key, get value from main koanf instance - if opt.KoanfKey != "" && opt.KoanfKey == options.RootActiveProfileOption.KoanfKey && mainKoanfInstance != nil { - kValue = mainKoanfInstance.KoanfInstance().Get(opt.KoanfKey) + if opt.KoanfKey != "" && strings.EqualFold(opt.KoanfKey, options.RootActiveProfileOption.KoanfKey) && mainKoanfInstance != nil { + kValue = mainKoanfInstance.KoanfInstance().Get("activeprofile") + if kValue == nil { + kValue = mainKoanfInstance.KoanfInstance().Get(opt.KoanfKey) + } } else { // // Case 2: --profile flag has been set, get value from set profile koanf instance // // Case 3: no --profile flag set, get value from active profile koanf instance defined in main koanf instance @@ -126,7 +129,7 @@ func (k KoanfConfig) ProfileNames() (profileNames []string) { mainKoanfKeys := k.KoanfInstance().All() for key := range mainKoanfKeys { // Do not add Active profile koanf key to profileNames - if key == options.RootActiveProfileOption.KoanfKey { + if strings.EqualFold(key, options.RootActiveProfileOption.KoanfKey) { continue } @@ -230,6 +233,34 @@ func (k KoanfConfig) GetProfileKoanf(pName string) (subKoanf *koanf.Koanf, err e } func (k KoanfConfig) WriteFile() (err error) { + // Support for legacy viper keys + for _, profileName := range k.ProfileNames() { + for key, val := range k.KoanfInstance().All() { + if profileName == key || !strings.Contains(key, profileName) { + continue + } + for _, opt := range options.Options() { + fullKoanfKeyValue := fmt.Sprintf("%s.%s", profileName, opt.KoanfKey) + if fullKoanfKeyValue == key { + continue + } + if strings.ToLower(fullKoanfKeyValue) == key { + err = k.KoanfInstance().Set(fullKoanfKeyValue, val) + if err != nil { + return fmt.Errorf("error setting koanf key %s: %w", fullKoanfKeyValue, err) + } + k.KoanfInstance().Delete(key) + } + } + } + } + + // Delete the original active profile key if it exists and the new activeProfile exists + originalActiveProfileKey := strings.ToLower(options.RootActiveProfileOption.KoanfKey) + if k.KoanfInstance().Exists(originalActiveProfileKey) && k.KoanfInstance().Exists(options.RootActiveProfileOption.KoanfKey) { + k.KoanfInstance().Delete(strings.ToLower(originalActiveProfileKey)) + } + encodedConfig, err := k.KoanfInstance().Marshal(yaml.Parser()) if err != nil { return fmt.Errorf("error marshalling koanf: %w", err) @@ -291,7 +322,7 @@ func (k KoanfConfig) DefaultMissingKoanfKeys() (err error) { } for _, opt := range options.Options() { - if opt.KoanfKey == "" || opt.KoanfKey == options.RootActiveProfileOption.KoanfKey { + if opt.KoanfKey == "" || strings.EqualFold(opt.KoanfKey, options.RootActiveProfileOption.KoanfKey) { continue } diff --git a/internal/profiles/validate_test.go b/internal/profiles/validate_test.go index 54fc324a..503116aa 100644 --- a/internal/profiles/validate_test.go +++ b/internal/profiles/validate_test.go @@ -19,6 +19,16 @@ func TestValidate(t *testing.T) { } } +// Test Validate function with legacy profile +func TestValidateLegacyProfile(t *testing.T) { + testutils_koanf.InitKoanfsCustomFile(t, testutils_koanf.ReturnDefaultLegacyConfigFileContents()) + + err := profiles.Validate() + if err == nil { + t.Errorf("Validate returned nil, expected error") + } +} + // Test Validate function with invalid uuid func TestValidateInvalidProfile(t *testing.T) { fileContents := `activeProfile: default diff --git a/internal/testing/testutils_koanf/koanf_utils.go b/internal/testing/testutils_koanf/koanf_utils.go index 66862f43..c0cd38d8 100644 --- a/internal/testing/testutils_koanf/koanf_utils.go +++ b/internal/testing/testutils_koanf/koanf_utils.go @@ -58,6 +58,43 @@ production: pingFederate: insecureTrustAllTLS: false xBypassExternalValidationHeader: false` + + defaultLegacyConfigFileContentsPattern string = `activeprofile: default +default: + description: "default description" + nocolor: true + outputformat: text + export: + outputdirectory: %s + servicegroup: %s + services: ["%s"] + service: + pingone: + regioncode: %s + authentication: + type: worker + worker: + clientid: %s + clientsecret: %s + environmentid: %s + pingfederate: + adminapipath: /pf-admin-api/v1 + authentication: + type: basicauth + basicauth: + username: Administrator + password: 2FederateM0re + httpshost: https://localhost:9999 + insecuretrustalltls: true + xbypassexternalvalidationheader: true +production: + description: "test profile description" + nocolor: true + outputformat: text + service: + pingfederate: + insecuretrustalltls: false + xbypassexternalvalidationheader: false` ) func CreateConfigFile(t *testing.T) string { @@ -115,3 +152,15 @@ func getDefaultConfigFileContents() string { os.Getenv("TEST_PINGONE_ENVIRONMENT_ID"), ) } + +func ReturnDefaultLegacyConfigFileContents() string { + return fmt.Sprintf(defaultLegacyConfigFileContentsPattern, + outputDirectoryReplacement, + customtypes.ENUM_EXPORT_SERVICE_GROUP_PINGONE, + customtypes.ENUM_EXPORT_SERVICE_PINGFEDERATE, + os.Getenv("TEST_PINGONE_REGION_CODE"), + os.Getenv("TEST_PINGONE_WORKER_CLIENT_ID"), + os.Getenv("TEST_PINGONE_WORKER_CLIENT_SECRET"), + os.Getenv("TEST_PINGONE_ENVIRONMENT_ID"), + ) +}