@@ -95,8 +95,18 @@ func (a *App) SSH(ctx context.Context, sshArgs []string, opts sshOptions) (err e
9595 return fmt .Errorf ("get or choose codespace: %w" , err )
9696 }
9797
98- session , err := openSSHSession (ctx , a , codespace , liveshareLogger )
98+ // While connecting, ensure in the background that the user has keys installed.
99+ // That lets us report a more useful error message if they don't.
100+ authkeys := make (chan error , 1 )
101+ go func () {
102+ authkeys <- a .ensureAuthorizedKeys (ctx )
103+ }()
104+
105+ session , err := a .openSSHSession (ctx , codespace , liveshareLogger )
99106 if err != nil {
107+ if authErr := <- authkeys ; authErr != nil {
108+ return authErr
109+ }
100110 return fmt .Errorf ("error connecting to codespace: %w" , err )
101111 }
102112 defer safeClose (session , & err )
@@ -201,7 +211,7 @@ func (a *App) printOpenSSHConfig(ctx context.Context, opts configOptions) error
201211 }
202212 }()
203213
204- session , err := openSSHSession (ctx , a , cs , nil )
214+ session , err := a . openSSHSession (ctx , cs , nil )
205215 if err != nil {
206216 result .err = fmt .Errorf ("error connecting to codespace: %w" , err )
207217 return
@@ -220,6 +230,12 @@ func (a *App) printOpenSSHConfig(ctx context.Context, opts configOptions) error
220230 }()
221231 }
222232
233+ // While the above fetches are running, ensure that the user has keys installed.
234+ // That lets us report a more useful error message if they don't.
235+ if err = a .ensureAuthorizedKeys (ctx ); err != nil {
236+ return err
237+ }
238+
223239 ghexec , err := os .Executable ()
224240 if err != nil {
225241 return err
@@ -284,19 +300,7 @@ type codespaceSSHConfig struct {
284300 GHExec string // path used for invoking the current `gh` binary
285301}
286302
287- func openSSHSession (ctx context.Context , a * App , codespace * api.Codespace , liveshareLogger * log.Logger ) (* liveshare.Session , error ) {
288- // TODO(josebalius): We can fetch the user in parallel to everything else
289- // we should convert this call and others to happen async
290- user , err := a .apiClient .GetUser (ctx )
291- if err != nil {
292- return nil , fmt .Errorf ("error getting user: %w" , err )
293- }
294-
295- authkeys := make (chan error , 1 )
296- go func () {
297- authkeys <- checkAuthorizedKeys (ctx , a .apiClient , user .Login )
298- }()
299-
303+ func (a * App ) openSSHSession (ctx context.Context , codespace * api.Codespace , liveshareLogger * log.Logger ) (* liveshare.Session , error ) {
300304 if liveshareLogger == nil {
301305 liveshareLogger = noopLogger ()
302306 }
@@ -306,12 +310,16 @@ func openSSHSession(ctx context.Context, a *App, codespace *api.Codespace, lives
306310 return nil , fmt .Errorf ("error connecting to codespace: %w" , err )
307311 }
308312
309- if err := <- authkeys ; err != nil {
310- session .Close ()
311- return nil , err
313+ return session , nil
314+ }
315+
316+ func (a * App ) ensureAuthorizedKeys (ctx context.Context ) error {
317+ user , err := a .apiClient .GetUser (ctx )
318+ if err != nil {
319+ return fmt .Errorf ("error getting user: %w" , err )
312320 }
313321
314- return session , nil
322+ return checkAuthorizedKeys ( ctx , a . apiClient , user . Login )
315323}
316324
317325type cpOptions struct {
0 commit comments