diff --git a/internal/cmd/auth/check.go b/internal/cmd/auth/check.go index 75825adb..323138c6 100644 --- a/internal/cmd/auth/check.go +++ b/internal/cmd/auth/check.go @@ -1,7 +1,6 @@ package auth import ( - psauth "github.com/planetscale/cli/internal/auth" "github.com/planetscale/cli/internal/cmdutil" "github.com/planetscale/cli/internal/printer" @@ -9,9 +8,6 @@ import ( ) func CheckCmd(ch *cmdutil.Helper) *cobra.Command { - var clientID string - var clientSecret string - cmd := &cobra.Command{ Use: "check", Args: cobra.NoArgs, @@ -49,7 +45,5 @@ func CheckCmd(ch *cmdutil.Helper) *cobra.Command { }, } - cmd.Flags().StringVar(&clientID, "client-id", psauth.OAuthClientID, "The client ID for the PlanetScale CLI application.") - cmd.Flags().StringVar(&clientSecret, "client-secret", psauth.OAuthClientSecret, "The client ID for the PlanetScale CLI application") return cmd } diff --git a/internal/cmd/auth/login.go b/internal/cmd/auth/login.go index 9e565342..b3d64036 100644 --- a/internal/cmd/auth/login.go +++ b/internal/cmd/auth/login.go @@ -33,6 +33,7 @@ func LoginCmd(ch *cmdutil.Helper) *cobra.Command { return errors.New("the 'login' command requires an interactive shell (use --format json; browser opens when possible, then polls until approved)") } + clientID, clientSecret = resolveOAuthClient(clientID, clientSecret) authenticator, err := psauth.New(cleanhttp.DefaultClient(), clientID, clientSecret, psauth.SetBaseURL(authURL)) if err != nil { if jsonMode { @@ -126,8 +127,7 @@ func LoginCmd(ch *cmdutil.Helper) *cobra.Command { }, } - cmd.Flags().StringVar(&clientID, "client-id", psauth.OAuthClientID, "The client ID for the PlanetScale CLI application.") - cmd.Flags().StringVar(&clientSecret, "client-secret", psauth.OAuthClientSecret, "The client ID for the PlanetScale CLI application") + addOAuthClientFlags(cmd, &clientID, &clientSecret) cmd.Flags().StringVar(&authURL, "api-url", psauth.DefaultBaseURL, "The PlanetScale Auth API base URL.") return cmd diff --git a/internal/cmd/auth/logout.go b/internal/cmd/auth/logout.go index aa7ca776..e333b0f8 100644 --- a/internal/cmd/auth/logout.go +++ b/internal/cmd/auth/logout.go @@ -33,6 +33,7 @@ func LogoutCmd(ch *cmdutil.Helper) *cobra.Command { _ = waitForEnter(cmd.InOrStdin()) } + clientID, clientSecret = resolveOAuthClient(clientID, clientSecret) authenticator, err := auth.New(cleanhttp.DefaultClient(), clientID, clientSecret, auth.SetBaseURL(apiURL)) if err != nil { return err @@ -56,8 +57,7 @@ func LogoutCmd(ch *cmdutil.Helper) *cobra.Command { }, } - cmd.Flags().StringVar(&clientID, "client-id", auth.OAuthClientID, "The client ID for the PlanetScale CLI application.") - cmd.Flags().StringVar(&clientSecret, "client-secret", auth.OAuthClientSecret, "The client ID for the PlanetScale CLI application") + addOAuthClientFlags(cmd, &clientID, &clientSecret) cmd.Flags().StringVar(&apiURL, "api-url", auth.DefaultBaseURL, "The PlanetScale base API URL.") return cmd } diff --git a/internal/cmd/auth/oauth_flags.go b/internal/cmd/auth/oauth_flags.go new file mode 100644 index 00000000..7dd128e6 --- /dev/null +++ b/internal/cmd/auth/oauth_flags.go @@ -0,0 +1,26 @@ +package auth + +import ( + psauth "github.com/planetscale/cli/internal/auth" + + "github.com/spf13/cobra" +) + +// addOAuthClientFlags registers --client-id and --client-secret without exposing +// the built-in OAuth credentials as help-text defaults. +func addOAuthClientFlags(cmd *cobra.Command, clientID, clientSecret *string) { + cmd.Flags().StringVar(clientID, "client-id", "", "The client ID for the PlanetScale CLI application.") + cmd.Flags().StringVar(clientSecret, "client-secret", "", "The client secret for the PlanetScale CLI application.") +} + +// resolveOAuthClient returns the flag values, falling back to the built-in +// PlanetScale CLI OAuth application credentials when unset. +func resolveOAuthClient(clientID, clientSecret string) (string, string) { + if clientID == "" { + clientID = psauth.OAuthClientID + } + if clientSecret == "" { + clientSecret = psauth.OAuthClientSecret + } + return clientID, clientSecret +} diff --git a/internal/cmd/auth/oauth_flags_test.go b/internal/cmd/auth/oauth_flags_test.go new file mode 100644 index 00000000..66a2322b --- /dev/null +++ b/internal/cmd/auth/oauth_flags_test.go @@ -0,0 +1,75 @@ +package auth + +import ( + "bytes" + "strings" + "testing" + + psauth "github.com/planetscale/cli/internal/auth" + "github.com/planetscale/cli/internal/cmdutil" + "github.com/spf13/cobra" +) + +func TestAuthLoginHelpOmitsOAuthSecrets(t *testing.T) { + assertHelpOmitsOAuthSecrets(t, LoginCmd(&cmdutil.Helper{})) +} + +func TestAuthLogoutHelpOmitsOAuthSecrets(t *testing.T) { + assertHelpOmitsOAuthSecrets(t, LogoutCmd(&cmdutil.Helper{})) +} + +func TestAuthCheckHasNoOAuthClientFlags(t *testing.T) { + cmd := CheckCmd(&cmdutil.Helper{}) + if cmd.Flags().Lookup("client-id") != nil { + t.Fatal("auth check must not define --client-id") + } + if cmd.Flags().Lookup("client-secret") != nil { + t.Fatal("auth check must not define --client-secret") + } +} + +func assertHelpOmitsOAuthSecrets(t *testing.T, cmd *cobra.Command) { + t.Helper() + + var out bytes.Buffer + cmd.SetOut(&out) + cmd.SetErr(&out) + cmd.SetArgs([]string{"--help"}) + if err := cmd.Execute(); err != nil { + t.Fatalf("help: %v", err) + } + + help := out.String() + if strings.Contains(help, psauth.OAuthClientID) { + t.Fatalf("help text must not include OAuth client ID; got:\n%s", help) + } + if strings.Contains(help, psauth.OAuthClientSecret) { + t.Fatalf("help text must not include OAuth client secret; got:\n%s", help) + } + if !strings.Contains(help, "--client-id") { + t.Fatalf("help text should still document --client-id; got:\n%s", help) + } + if !strings.Contains(help, "--client-secret") { + t.Fatalf("help text should still document --client-secret; got:\n%s", help) + } +} + +func TestResolveOAuthClientDefaults(t *testing.T) { + id, secret := resolveOAuthClient("", "") + if id != psauth.OAuthClientID { + t.Fatalf("client ID = %q, want built-in default", id) + } + if secret != psauth.OAuthClientSecret { + t.Fatalf("client secret = %q, want built-in default", secret) + } +} + +func TestResolveOAuthClientOverrides(t *testing.T) { + id, secret := resolveOAuthClient("custom-id", "custom-secret") + if id != "custom-id" { + t.Fatalf("client ID = %q, want custom-id", id) + } + if secret != "custom-secret" { + t.Fatalf("client secret = %q, want custom-secret", secret) + } +}