diff --git a/cmd/config/add_profile.go b/cmd/config/add_profile.go index fa7990de..7a5327fe 100644 --- a/cmd/config/add_profile.go +++ b/cmd/config/add_profile.go @@ -15,7 +15,7 @@ const ( pingcli config add-profile Add a new configuration profile with a specific name and description. - pingcli config add-profile --name MyDeveloperEnv --description "My awesome new profile for my development environment" + pingcli config add-profile --name myprofile --description "My awesome new profile for my development environment" Add a new configuration profile with a guided experience and set it as the active profile. pingcli config add-profile --set-active` diff --git a/cmd/config/add_profile_test.go b/cmd/config/add_profile_test.go index 59989029..c2e35845 100644 --- a/cmd/config/add_profile_test.go +++ b/cmd/config/add_profile_test.go @@ -49,7 +49,7 @@ func TestConfigAddProfileCmd_DuplicateProfileName(t *testing.T) { // Test config add profile command fails when provided an invalid profile name func TestConfigAddProfileCmd_InvalidProfileName(t *testing.T) { - expectedErrorPattern := `^failed to add profile: invalid profile name: '.*'\. name must contain only alphanumeric characters, underscores, and dashes$` + expectedErrorPattern := `^failed to add profile: invalid profile name: '.*'\. name must be lowercase and contain only alphanumeric characters, underscores, and dashes$` err := testutils_cobra.ExecutePingcli(t, "config", "add-profile", "--name", "pname&*^*&^$&@!", "--description", "test description", @@ -57,6 +57,16 @@ func TestConfigAddProfileCmd_InvalidProfileName(t *testing.T) { testutils.CheckExpectedError(t, err, &expectedErrorPattern) } +// Test Root Command fails when provided an invalid value containing uppercase character for profile name +func TestConfigAddProfileCmd_InvalidUpperCaseProfileName(t *testing.T) { + expectedErrorPattern := `^failed to add profile: invalid profile name: '.*'\. name must be lowercase and contain only alphanumeric characters, underscores, and dashes$` + err := testutils_cobra.ExecutePingcli(t, "config", "add-profile", + "--name", "myProfile", + "--description", "test description", + "--set-active=false") + testutils.CheckExpectedError(t, err, &expectedErrorPattern) +} + // Test config add profile command fails when provided an invalid set-active value func TestConfigAddProfileCmd_InvalidSetActiveValue(t *testing.T) { expectedErrorPattern := `^invalid argument ".*" for "-s, --set-active" flag: strconv\.ParseBool: parsing ".*": invalid syntax$` diff --git a/cmd/config/config_test.go b/cmd/config/config_test.go index b69c2afe..a53f7663 100644 --- a/cmd/config/config_test.go +++ b/cmd/config/config_test.go @@ -35,7 +35,7 @@ func TestConfigCmd_HelpFlag(t *testing.T) { // expectedErrorPattern := `^failed to update profile '.*' name to: .*\. invalid profile name: '.*' profile does not exist$` // err := testutils_cobra.ExecutePingcli(t, "config", // "--profile", "nonexistent", -// "--name", "myProfile", +// "--name", "myprofile", // "--description", "hello") // testutils.CheckExpectedError(t, err, &expectedErrorPattern) @@ -46,7 +46,7 @@ func TestConfigCmd_HelpFlag(t *testing.T) { // expectedErrorPattern := `^failed to update profile '.*' name to: .*\. '.*' is the active profile and cannot be deleted$` // err := testutils_cobra.ExecutePingcli(t, "config", // "--profile", "default", -// "--name", "myProfile", +// "--name", "myprofile", // "--description", "hello") // testutils.CheckExpectedError(t, err, &expectedErrorPattern) @@ -54,7 +54,7 @@ func TestConfigCmd_HelpFlag(t *testing.T) { // // Test Config Command fails when provided an invalid profile name // func TestConfigCmd_InvalidProfileName(t *testing.T) { -// expectedErrorPattern := `^failed to update profile '.*' name to: .*\. invalid profile name: '.*'\. name must contain only alphanumeric characters, underscores, and dashes$` +// expectedErrorPattern := `^failed to update profile '.*' name to: .*\. invalid profile name: '.*'\. name must be lowercase and contain only alphanumeric characters, underscores, and dashes$` // err := testutils_cobra.ExecutePingcli(t, "config", // "--profile", "production", // "--name", "pname&*^*&^$&@!", diff --git a/cmd/config/delete_profile.go b/cmd/config/delete_profile.go index 0cb5f7e4..c0f15d74 100644 --- a/cmd/config/delete_profile.go +++ b/cmd/config/delete_profile.go @@ -16,10 +16,10 @@ const ( pingcli config delete-profile Delete a configuration profile by specifying the name of an existing configured profile. - pingcli config delete-profile MyDeveloperEnv + pingcli config delete-profile myprofile Delete a configuration profile by auto-accepting the deletion. - pingcli config delete-profile --yes MyDeveloperEnv` + pingcli config delete-profile --yes myprofile` ) func NewConfigDeleteProfileCommand() *cobra.Command { diff --git a/cmd/config/delete_profile_test.go b/cmd/config/delete_profile_test.go index ef6aaa8c..1fc65f80 100644 --- a/cmd/config/delete_profile_test.go +++ b/cmd/config/delete_profile_test.go @@ -43,7 +43,7 @@ func TestConfigDeleteProfileCmd_ActiveProfile(t *testing.T) { // Test Config delete-profile Command fails when provided an invalid profile name func TestConfigDeleteProfileCmd_InvalidProfileName(t *testing.T) { - expectedErrorPattern := `^failed to delete profile: invalid profile name: '.*'\. name must contain only alphanumeric characters, underscores, and dashes$` + expectedErrorPattern := `^failed to delete profile: invalid profile name: '.*' profile does not exist$` err := testutils_cobra.ExecutePingcli(t, "config", "delete-profile", "--yes", "pname&*^*&^$&@!") testutils.CheckExpectedError(t, err, &expectedErrorPattern) } diff --git a/cmd/config/get.go b/cmd/config/get.go index 0f9b3def..338b9396 100644 --- a/cmd/config/get.go +++ b/cmd/config/get.go @@ -12,8 +12,8 @@ const ( configGetCommandExamples = ` Read all the configuration settings for the PingOne service in the active (or default) profile. pingcli config get pingone - Read the noColor setting for the profile named 'myProfile'. - pingcli config get --profile myProfile noColor + Read the noColor setting for the profile named 'myprofile'. + pingcli config get --profile myprofile noColor Read the worker ID used to authenticate to the PingOne service management API. pingcli config get service.pingone.authentication.worker.environmentID diff --git a/cmd/config/set.go b/cmd/config/set.go index 2512476d..5b6505ed 100644 --- a/cmd/config/set.go +++ b/cmd/config/set.go @@ -12,11 +12,11 @@ const ( configSetCommandExamples = ` Set the color setting to true for the currently active profile. pingcli config set color=true - Set the PingOne tenant region code setting to 'AP' for the profile named 'myProfile'. - pingcli config set --profile myProfile service.pingone.regionCode=AP + Set the PingOne tenant region code setting to 'AP' for the profile named 'myprofile'. + pingcli config set --profile myprofile service.pingone.regionCode=AP Set the PingFederate basic authentication password with unmasked output - pingcli config set --profile myProfile --unmask-values service.pingfederate.authentication.basicAuth.password=1234` + pingcli config set --profile myprofile --unmask-values service.pingfederate.authentication.basicAuth.password=1234` ) func NewConfigSetCommand() *cobra.Command { diff --git a/cmd/config/set_active_profile_test.go b/cmd/config/set_active_profile_test.go index 82c171d1..1fa511c3 100644 --- a/cmd/config/set_active_profile_test.go +++ b/cmd/config/set_active_profile_test.go @@ -42,7 +42,7 @@ func TestConfigSetActiveProfileCmd_ActiveProfile(t *testing.T) { // Test Config set-active-profile Command fails when provided an invalid profile name func TestConfigSetActiveProfileCmd_InvalidProfileName(t *testing.T) { - expectedErrorPattern := `^failed to set active profile: invalid profile name: '.*'\. name must contain only alphanumeric characters, underscores, and dashes$` + expectedErrorPattern := `^failed to set active profile: invalid profile name: '.*' profile does not exist$` err := testutils_cobra.ExecutePingcli(t, "config", "set-active-profile", "pname&*^*&^$&@!") testutils.CheckExpectedError(t, err, &expectedErrorPattern) } diff --git a/cmd/config/unset.go b/cmd/config/unset.go index e3ce5674..09a6efae 100644 --- a/cmd/config/unset.go +++ b/cmd/config/unset.go @@ -12,8 +12,8 @@ const ( configUnsetCommandExamples = ` Unset the color setting for the currently active profile. pingcli config unset color - Unset the PingOne tenant region code setting for the profile named 'myProfile'. - pingcli config unset --profile myProfile service.pingone.regionCode` + Unset the PingOne tenant region code setting for the profile named 'myprofile'. + pingcli config unset --profile myprofile service.pingone.regionCode` ) func NewConfigUnsetCommand() *cobra.Command { diff --git a/cmd/config/view_profile_test.go b/cmd/config/view_profile_test.go index 93b2c9ed..5aeb0e31 100644 --- a/cmd/config/view_profile_test.go +++ b/cmd/config/view_profile_test.go @@ -40,7 +40,7 @@ func TestConfigViewProfileCmd_Execute_NonExistentProfile(t *testing.T) { // Test Config Set Command fails with invalid profile func TestConfigViewProfileCmd_Execute_InvalidProfile(t *testing.T) { - expectedErrorPattern := `^failed to view profile: invalid profile name: '.*'\. name must contain only alphanumeric characters, underscores, and dashes$` + expectedErrorPattern := `^failed to view profile: invalid profile name: '.*' profile does not exist$` err := testutils_cobra.ExecutePingcli(t, "config", "view-profile", "(*&*(#))") testutils.CheckExpectedError(t, err, &expectedErrorPattern) } diff --git a/internal/commands/config/delete_profile_internal.go b/internal/commands/config/delete_profile_internal.go index 6573474c..d2f4f210 100644 --- a/internal/commands/config/delete_profile_internal.go +++ b/internal/commands/config/delete_profile_internal.go @@ -21,6 +21,10 @@ func RunInternalConfigDeleteProfile(args []string, rc io.ReadCloser) (err error) } } + if err = profiles.GetMainConfig().ValidateExistingProfileName(pName); err != nil { + return fmt.Errorf("failed to delete profile: %v", err) + } + confirmed, err := promptUserToConfirmDelete(pName, rc) if err != nil { return fmt.Errorf("failed to delete profile: %v", err) diff --git a/internal/commands/config/delete_profile_internal_test.go b/internal/commands/config/delete_profile_internal_test.go index 3ce47d0b..c47ba362 100644 --- a/internal/commands/config/delete_profile_internal_test.go +++ b/internal/commands/config/delete_profile_internal_test.go @@ -28,7 +28,7 @@ func Test_deleteProfile_ActiveProfile(t *testing.T) { func Test_deleteProfile_InvalidProfileName(t *testing.T) { testutils_viper.InitVipers(t) - expectedErrorPattern := `^invalid profile name: '.*'\. name must contain only alphanumeric characters, underscores, and dashes$` + expectedErrorPattern := `^invalid profile name: '.*' profile does not exist$` err := deleteProfile("(*#&)") testutils.CheckExpectedError(t, err, &expectedErrorPattern) } diff --git a/internal/commands/config/get_internal.go b/internal/commands/config/get_internal.go index 928b6845..91c0bad5 100644 --- a/internal/commands/config/get_internal.go +++ b/internal/commands/config/get_internal.go @@ -20,7 +20,7 @@ func RunInternalConfigGet(viperKey string) (err error) { return fmt.Errorf("failed to get configuration: %v", err) } - msgStr := fmt.Sprintf("Configuration values for profile '%s' and key '%s':\n", pName, viperKey) + msgStr := fmt.Sprintf("Configuration values for profile '%s' and key '%s':\n", strings.ToLower(pName), viperKey) for _, opt := range options.Options() { if opt.ViperKey == "" || !strings.Contains(opt.ViperKey, viperKey) { diff --git a/internal/commands/config/set_active_profile_internal_test.go b/internal/commands/config/set_active_profile_internal_test.go index e115cb72..5e31db1a 100644 --- a/internal/commands/config/set_active_profile_internal_test.go +++ b/internal/commands/config/set_active_profile_internal_test.go @@ -20,7 +20,7 @@ func Test_RunInternalConfigSetActiveProfile(t *testing.T) { func Test_RunInternalConfigSetActiveProfile_InvalidProfileName(t *testing.T) { testutils_viper.InitVipers(t) - expectedErrorPattern := `^failed to set active profile: invalid profile name: '.*'\. name must contain only alphanumeric characters, underscores, and dashes$` + expectedErrorPattern := `^failed to set active profile: invalid profile name: '.*' profile does not exist$` err := RunInternalConfigSetActiveProfile([]string{"(*#&)"}, os.Stdin) testutils.CheckExpectedError(t, err, &expectedErrorPattern) } diff --git a/internal/commands/config/set_internal_test.go b/internal/commands/config/set_internal_test.go index e8743d73..89976eb9 100644 --- a/internal/commands/config/set_internal_test.go +++ b/internal/commands/config/set_internal_test.go @@ -81,7 +81,7 @@ func Test_RunInternalConfigSet_InvalidProfileName(t *testing.T) { options.RootProfileOption.Flag.Changed = true options.RootProfileOption.CobraParamValue = &profileName - expectedErrorPattern := `^failed to set configuration: invalid profile name: '.*'\. name must contain only alphanumeric characters, underscores, and dashes$` + expectedErrorPattern := `^failed to set configuration: invalid profile name: '.*' profile does not exist$` err := RunInternalConfigSet("noColor=true") testutils.CheckExpectedError(t, err, &expectedErrorPattern) } diff --git a/internal/profiles/validate.go b/internal/profiles/validate.go index 43574190..f9a7e40d 100644 --- a/internal/profiles/validate.go +++ b/internal/profiles/validate.go @@ -15,6 +15,11 @@ func Validate() (err error) { // Get a slice of all profile names configured in the config.yaml file profileNames := GetMainConfig().ProfileNames() + // Iterate over the profileNames and convert each to lowercase + for i := range profileNames { + profileNames[i] = strings.ToLower(profileNames[i]) + } + // Validate profile names if err = validateProfileNames(profileNames); err != nil { return err @@ -22,6 +27,7 @@ func Validate() (err error) { // Make sure selected active profile is in the configuration file activeProfileName, err := GetOptionValue(options.RootActiveProfileOption) + activeProfileName = strings.ToLower(activeProfileName) if err != nil { return fmt.Errorf("failed to validate Ping CLI configuration: %v", err) } diff --git a/internal/profiles/viper.go b/internal/profiles/viper.go index bceee07b..c013f761 100644 --- a/internal/profiles/viper.go +++ b/internal/profiles/viper.go @@ -219,14 +219,14 @@ func (m MainConfig) SaveProfile(pName string, subViper *viper.Viper) (err error) return nil } -// The profile name format must be valid // The profile name must exist func (m MainConfig) ValidateExistingProfileName(pName string) (err error) { - if err := m.ValidateProfileNameFormat(pName); err != nil { - return err + if pName == "" { + return fmt.Errorf("invalid profile name: profile name cannot be empty") } pNames := m.ProfileNames() + if !slices.ContainsFunc(pNames, func(n string) bool { return strings.EqualFold(n, pName) }) { @@ -260,9 +260,9 @@ func (m MainConfig) ValidateProfileNameFormat(pName string) (err error) { return fmt.Errorf("invalid profile name: profile name cannot be empty") } - re := regexp.MustCompile(`^[a-zA-Z0-9\_\-]+$`) + re := regexp.MustCompile(`^[a-z0-9\_\-]+$`) if !re.MatchString(pName) { - return fmt.Errorf("invalid profile name: '%s'. name must contain only alphanumeric characters, underscores, and dashes", pName) + return fmt.Errorf("invalid profile name: '%s'. name must be lowercase and contain only alphanumeric characters, underscores, and dashes", pName) } return nil