@@ -43,6 +43,11 @@ const (
4343 ProtocolReconnectingPTY = "reconnecting-pty"
4444 ProtocolSSH = "ssh"
4545 ProtocolDial = "dial"
46+
47+ // MagicSessionErrorCode indicates that something went wrong with the session, rather than the
48+ // command just returning a nonzero exit code, and is chosen as an arbitrary, high number
49+ // unlikely to shadow other exit codes, which are typically 1, 2, 3, etc.
50+ MagicSessionErrorCode = 229
4651)
4752
4853type Options struct {
@@ -273,9 +278,17 @@ func (a *agent) init(ctx context.Context) {
273278 },
274279 Handler : func (session ssh.Session ) {
275280 err := a .handleSSHSession (session )
281+ var exitError * exec.ExitError
282+ if xerrors .As (err , & exitError ) {
283+ a .logger .Debug (ctx , "ssh session returned" , slog .Error (exitError ))
284+ _ = session .Exit (exitError .ExitCode ())
285+ return
286+ }
276287 if err != nil {
277288 a .logger .Warn (ctx , "ssh session failed" , slog .Error (err ))
278- _ = session .Exit (1 )
289+ // This exit code is designed to be unlikely to be confused for a legit exit code
290+ // from the process.
291+ _ = session .Exit (MagicSessionErrorCode )
279292 return
280293 }
281294 },
@@ -403,7 +416,7 @@ func (a *agent) createCommand(ctx context.Context, rawCommand string, env []stri
403416 return cmd , nil
404417}
405418
406- func (a * agent ) handleSSHSession (session ssh.Session ) error {
419+ func (a * agent ) handleSSHSession (session ssh.Session ) ( retErr error ) {
407420 cmd , err := a .createCommand (session .Context (), session .RawCommand (), session .Environ ())
408421 if err != nil {
409422 return err
@@ -426,14 +439,24 @@ func (a *agent) handleSSHSession(session ssh.Session) error {
426439 if err != nil {
427440 return xerrors .Errorf ("start command: %w" , err )
428441 }
442+ defer func () {
443+ closeErr := ptty .Close ()
444+ if closeErr != nil {
445+ a .logger .Warn (context .Background (), "failed to close tty" ,
446+ slog .Error (closeErr ))
447+ if retErr == nil {
448+ retErr = closeErr
449+ }
450+ }
451+ }()
429452 err = ptty .Resize (uint16 (sshPty .Window .Height ), uint16 (sshPty .Window .Width ))
430453 if err != nil {
431454 return xerrors .Errorf ("resize ptty: %w" , err )
432455 }
433456 go func () {
434457 for win := range windowSize {
435- err = ptty .Resize (uint16 (win .Height ), uint16 (win .Width ))
436- if err != nil {
458+ resizeErr : = ptty .Resize (uint16 (win .Height ), uint16 (win .Width ))
459+ if resizeErr != nil {
437460 a .logger .Warn (context .Background (), "failed to resize tty" , slog .Error (err ))
438461 }
439462 }
@@ -444,9 +467,15 @@ func (a *agent) handleSSHSession(session ssh.Session) error {
444467 go func () {
445468 _ , _ = io .Copy (session , ptty .Output ())
446469 }()
447- _ , _ = process .Wait ()
448- _ = ptty .Close ()
449- return nil
470+ err = process .Wait ()
471+ var exitErr * exec.ExitError
472+ // ExitErrors just mean the command we run returned a non-zero exit code, which is normal
473+ // and not something to be concerned about. But, if it's something else, we should log it.
474+ if err != nil && ! xerrors .As (err , & exitErr ) {
475+ a .logger .Warn (context .Background (), "wait error" ,
476+ slog .Error (err ))
477+ }
478+ return err
450479 }
451480
452481 cmd .Stdout = session
@@ -549,7 +578,7 @@ func (a *agent) handleReconnectingPTY(ctx context.Context, rawID string, conn ne
549578 go func () {
550579 // If the process dies randomly, we should
551580 // close the pty.
552- _ , _ = process .Wait ()
581+ _ = process .Wait ()
553582 rpty .Close ()
554583 }()
555584 go func () {
0 commit comments