@@ -79,7 +79,11 @@ Examples:
7979 Args : cobra .MaximumNArgs (1 ),
8080 ValidArgsFunction : serviceIDCompletion ,
8181 RunE : func (cmd * cobra.Command , args []string ) error {
82- service , err := getServiceDetails (cmd , args )
82+ cfg , projectID , client , err := loadConfigAndApiClient ()
83+ if err != nil {
84+ return err
85+ }
86+ service , err := getServiceDetails (cmd , cfg , projectID , client , args )
8387 if err != nil {
8488 return err
8589 }
@@ -131,7 +135,9 @@ with the appropriate connection parameters.
131135Authentication is handled automatically using:
1321361. Stored password (keyring, ~/.pgpass, or none based on --password-storage setting)
1331372. PGPASSWORD environment variable
134- 3. Interactive password prompt (if neither above is available)
138+ 3. If authentication fails, offers interactive options:
139+ - Enter password manually (will be saved for future use)
140+ - Reset password (update or generates a new password via the API)
135141
136142Examples:
137143 # Connect to default service
@@ -158,8 +164,11 @@ Examples:
158164 RunE : func (cmd * cobra.Command , args []string ) error {
159165 // Separate service ID from additional psql flags
160166 serviceArgs , psqlFlags := separateServiceAndPsqlArgs (cmd , args )
161-
162- service , err := getServiceDetails (cmd , serviceArgs )
167+ cfg , projectID , client , err := loadConfigAndApiClient ()
168+ if err != nil {
169+ return err
170+ }
171+ service , err := getServiceDetails (cmd , cfg , projectID , client , serviceArgs )
163172 if err != nil {
164173 return err
165174 }
@@ -182,8 +191,7 @@ Examples:
182191 return fmt .Errorf ("connection pooler not available for this service" )
183192 }
184193
185- // Launch psql with additional flags
186- return launchPsqlWithConnectionString (details .String (), psqlPath , psqlFlags , service , dbConnectRole , cmd )
194+ return connectWithPasswordMenu (cmd .Context (), cmd , client , service , details , psqlPath , psqlFlags )
187195 },
188196 }
189197
@@ -232,7 +240,11 @@ Examples:
232240 Args : cobra .MaximumNArgs (1 ),
233241 ValidArgsFunction : serviceIDCompletion ,
234242 RunE : func (cmd * cobra.Command , args []string ) error {
235- service , err := getServiceDetails (cmd , args )
243+ cfg , projectID , client , err := loadConfigAndApiClient ()
244+ if err != nil {
245+ return err
246+ }
247+ service , err := getServiceDetails (cmd , cfg , projectID , client , args )
236248 if err != nil {
237249 return common .ExitWithCode (common .ExitInvalidParameters , err )
238250 }
@@ -306,7 +318,11 @@ Examples:
306318 Args : cobra .MaximumNArgs (1 ),
307319 ValidArgsFunction : serviceIDCompletion ,
308320 RunE : func (cmd * cobra.Command , args []string ) error {
309- service , err := getServiceDetailsFunc (cmd , args )
321+ cfg , projectID , client , err := loadConfigAndApiClient ()
322+ if err != nil {
323+ return err
324+ }
325+ service , err := getServiceDetailsFunc (cmd , cfg , projectID , client , args )
310326 if err != nil {
311327 return err
312328 }
@@ -651,10 +667,9 @@ PostgreSQL Configuration Parameters That May Be Set:
651667
652668 cmd .SilenceUsage = true
653669
654- // Get config
655- cfg , err := config .Load ()
670+ cfg , projectID , client , err := loadConfigAndApiClient ()
656671 if err != nil {
657- return fmt . Errorf ( "failed to load config: %w" , err )
672+ return err
658673 }
659674
660675 // Get password
@@ -664,7 +679,7 @@ PostgreSQL Configuration Parameters That May Be Set:
664679 }
665680
666681 // Get service details
667- service , err := getServiceDetails (cmd , args )
682+ service , err := getServiceDetails (cmd , cfg , projectID , client , args )
668683 if err != nil {
669684 return err
670685 }
@@ -748,34 +763,39 @@ func buildDbCmd() *cobra.Command {
748763 return cmd
749764}
750765
751- // getServiceDetails is a helper that handles common service lookup logic and returns the service details
752- func getServiceDetails (cmd * cobra.Command , args []string ) (api.Service , error ) {
753- // Get config
766+ func loadConfigAndApiClient () (* config.Config , string , * api.ClientWithResponses , error ) {
767+ // Load config
754768 cfg , err := config .Load ()
755769 if err != nil {
756- return api. Service {} , fmt .Errorf ("failed to load config: %w" , err )
770+ return nil , "" , nil , fmt .Errorf ("failed to load config: %w" , err )
757771 }
758772
759- // Determine service ID
760- serviceID , err := getServiceID (cfg , args )
761- if err != nil {
762- return api.Service {}, err
763- }
764-
765- cmd .SilenceUsage = true
766-
767773 // Get API key and project ID for authentication
768774 apiKey , projectID , err := getCredentialsForDB ()
769775 if err != nil {
770- return api. Service {} , common .ExitWithCode (common .ExitAuthenticationError , fmt .Errorf ("authentication required: %w. Please run 'tiger auth login'" , err ))
776+ return nil , "" , nil , common .ExitWithCode (common .ExitAuthenticationError , fmt .Errorf ("authentication required: %w. Please run 'tiger auth login'" , err ))
771777 }
772778
773779 // Create API client
774780 client , err := api .NewTigerClient (cfg , apiKey )
775781 if err != nil {
776- return api. Service {} , fmt .Errorf ("failed to create API client: %w" , err )
782+ return nil , "" , nil , fmt .Errorf ("failed to create API client: %w" , err )
777783 }
778784
785+ return cfg , projectID , client , nil
786+ }
787+
788+ // getServiceDetails is a helper that handles common service lookup logic and returns the service details
789+ func getServiceDetails (cmd * cobra.Command , cfg * config.Config , projectID string , client * api.ClientWithResponses , args []string ) (api.Service , error ) {
790+
791+ // Determine service ID
792+ serviceID , err := getServiceID (cfg , args )
793+ if err != nil {
794+ return api.Service {}, err
795+ }
796+
797+ cmd .SilenceUsage = true
798+
779799 // Fetch service details
780800 ctx , cancel := context .WithTimeout (cmd .Context (), 30 * time .Second )
781801 defer cancel ()
@@ -820,17 +840,22 @@ func separateServiceAndPsqlArgs(cmd ArgsLenAtDashProvider, args []string) ([]str
820840 return serviceArgs , psqlFlags
821841}
822842
823- // launchPsqlWithConnectionString launches psql using the connection string and additional flags
824- func launchPsqlWithConnectionString (connectionString , psqlPath string , additionalFlags []string , service api.Service , role string , cmd * cobra.Command ) error {
825- psqlCmd := buildPsqlCommand (connectionString , psqlPath , additionalFlags , service , role , cmd )
843+ // launchPsql launches psql using the connection string and additional flags.
844+ // It retrieves the password from storage and sets PGPASSWORD environment variable.
845+ func launchPsql (details * common.ConnectionDetails , psqlPath string , additionalFlags []string , service api.Service , cmd * cobra.Command ) error {
846+ psqlCmd := buildPsqlCommand (details , psqlPath , additionalFlags , service , cmd )
826847 return psqlCmd .Run ()
827848}
828849
829850// buildPsqlCommand creates the psql command with proper environment setup
830- func buildPsqlCommand (connectionString , psqlPath string , additionalFlags []string , service api.Service , role string , cmd * cobra.Command ) * exec.Cmd {
831- // Build command arguments: connection string first, then additional flags
832- // Note: connectionString contains only "postgresql://user@host:port/db" - no password
851+ func buildPsqlCommand (details * common. ConnectionDetails , psqlPath string , additionalFlags []string , service api.Service , cmd * cobra.Command ) * exec.Cmd {
852+ password := details . Password
853+ // Ensure we don't include password in the connection string to make it not show up in process lists
833854 // Passwords are passed via PGPASSWORD environment variable (see below)
855+ detailsCopy := * details
856+ detailsCopy .Password = ""
857+ connectionString := detailsCopy .String ()
858+ // Build command arguments: connection string first, then additional flags
834859 args := []string {connectionString }
835860 args = append (args , additionalFlags ... )
836861
@@ -841,16 +866,21 @@ func buildPsqlCommand(connectionString, psqlPath string, additionalFlags []strin
841866 psqlCmd .Stdout = cmd .OutOrStdout ()
842867 psqlCmd .Stderr = cmd .ErrOrStderr ()
843868
844- // Only set PGPASSWORD for keyring storage method
845- // pgpass storage relies on psql automatically reading ~/.pgpass file
846- storage := common .GetPasswordStorage ()
847- if _ , isKeyring := storage .(* common.KeyringStorage ); isKeyring {
848- if password , err := storage .Get (service , role ); err == nil && password != "" {
849- // Set PGPASSWORD environment variable for psql when using keyring
850- psqlCmd .Env = append (os .Environ (), "PGPASSWORD=" + password )
869+ // Use provided password directly if available
870+ if password != "" {
871+ psqlCmd .Env = append (os .Environ (), "PGPASSWORD=" + password )
872+ } else {
873+ storage := common .GetPasswordStorage ()
874+ // Only set PGPASSWORD for keyring storage method
875+ // pgpass storage relies on psql automatically reading ~/.pgpass file
876+ if _ , isKeyring := storage .(* common.KeyringStorage ); isKeyring {
877+ if storedPassword , err := storage .Get (service , details .Role ); err == nil && storedPassword != "" {
878+ // Set PGPASSWORD environment variable for psql when using keyring
879+ psqlCmd .Env = append (os .Environ (), "PGPASSWORD=" + storedPassword )
880+ }
881+ // Note: If keyring password retrieval fails, we let psql try without it
882+ // This allows fallback to other authentication methods
851883 }
852- // Note: If keyring password retrieval fails, we let psql try without it
853- // This allows fallback to other authentication methods
854884 }
855885
856886 return psqlCmd
0 commit comments