@@ -374,7 +374,7 @@ func (a *agent) runStartupScript(ctx context.Context, script string) error {
374
374
return nil
375
375
}
376
376
377
- writer ,err := os .OpenFile (filepath .Join (os .TempDir (),"coder-startup-script.log" ),os .O_CREATE | os .O_RDWR ,0600 )
377
+ writer ,err := os .OpenFile (filepath .Join (os .TempDir (),"coder-startup-script.log" ),os .O_CREATE | os .O_RDWR ,0o600 )
378
378
if err != nil {
379
379
return xerrors .Errorf ("open startup script log file: %w" ,err )
380
380
}
@@ -537,6 +537,8 @@ func (a *agent) init(ctx context.Context) {
537
537
},
538
538
SubsystemHandlers :map [string ]ssh.SubsystemHandler {
539
539
"sftp" :func (session ssh.Session ) {
540
+ session .DisablePTYEmulation ()
541
+
540
542
server ,err := sftp .NewServer (session )
541
543
if err != nil {
542
544
a .logger .Debug (session .Context (),"initialize sftp server" ,slog .Error (err ))
@@ -661,7 +663,8 @@ func (a *agent) createCommand(ctx context.Context, rawCommand string, env []stri
661
663
}
662
664
663
665
func (a * agent )handleSSHSession (session ssh.Session ) (retErr error ) {
664
- cmd ,err := a .createCommand (session .Context (),session .RawCommand (),session .Environ ())
666
+ ctx := session .Context ()
667
+ cmd ,err := a .createCommand (ctx ,session .RawCommand (),session .Environ ())
665
668
if err != nil {
666
669
return err
667
670
}
@@ -678,32 +681,34 @@ func (a *agent) handleSSHSession(session ssh.Session) (retErr error) {
678
681
679
682
sshPty ,windowSize ,isPty := session .Pty ()
680
683
if isPty {
684
+ // Disable minimal PTY emulation set by gliderlabs/ssh (NL-to-CRNL).
685
+ // See https://github.com/coder/coder/issues/3371.
686
+ session .DisablePTYEmulation ()
687
+
681
688
cmd .Env = append (cmd .Env ,fmt .Sprintf ("TERM=%s" ,sshPty .Term ))
682
689
683
690
// The pty package sets `SSH_TTY` on supported platforms.
684
- ptty ,process ,err := pty .Start (cmd )
691
+ ptty ,process ,err := pty .Start (cmd ,pty .WithPTYOptions (
692
+ pty .WithSSHRequest (sshPty ),
693
+ pty .WithLogger (slog .Stdlib (ctx ,a .logger ,slog .LevelInfo )),
694
+ ))
685
695
if err != nil {
686
696
return xerrors .Errorf ("start command: %w" ,err )
687
697
}
688
698
defer func () {
689
699
closeErr := ptty .Close ()
690
700
if closeErr != nil {
691
- a .logger .Warn (context .Background (),"failed to close tty" ,
692
- slog .Error (closeErr ))
701
+ a .logger .Warn (ctx ,"failed to close tty" ,slog .Error (closeErr ))
693
702
if retErr == nil {
694
703
retErr = closeErr
695
704
}
696
705
}
697
706
}()
698
- err = ptty .Resize (uint16 (sshPty .Window .Height ),uint16 (sshPty .Window .Width ))
699
- if err != nil {
700
- return xerrors .Errorf ("resize ptty: %w" ,err )
701
- }
702
707
go func () {
703
708
for win := range windowSize {
704
709
resizeErr := ptty .Resize (uint16 (win .Height ),uint16 (win .Width ))
705
710
if resizeErr != nil {
706
- a .logger .Warn (context . Background () ,"failed to resize tty" ,slog .Error (resizeErr ))
711
+ a .logger .Warn (ctx ,"failed to resize tty" ,slog .Error (resizeErr ))
707
712
}
708
713
}
709
714
}()
@@ -718,8 +723,7 @@ func (a *agent) handleSSHSession(session ssh.Session) (retErr error) {
718
723
// ExitErrors just mean the command we run returned a non-zero exit code, which is normal
719
724
// and not something to be concerned about. But, if it's something else, we should log it.
720
725
if err != nil && ! xerrors .As (err ,& exitErr ) {
721
- a .logger .Warn (context .Background (),"wait error" ,
722
- slog .Error (err ))
726
+ a .logger .Warn (ctx ,"wait error" ,slog .Error (err ))
723
727
}
724
728
return err
725
729
}