5
5
"context"
6
6
"crypto/rand"
7
7
"crypto/rsa"
8
+ "crypto/sha256"
8
9
"errors"
9
10
"fmt"
10
11
"io"
@@ -274,7 +275,7 @@ func (s *Server) sessionStart(session ssh.Session, extraEnv []string) (retErr er
274
275
magicTypeLabel := magicTypeMetricLabel (magicType )
275
276
sshPty , windowSize , isPty := session .Pty ()
276
277
277
- cmd , err := s .CreateCommand (ctx , session .RawCommand (), env )
278
+ cmd , cleanup , err := s .CreateCommand (ctx , session .RawCommand (), env )
278
279
if err != nil {
279
280
ptyLabel := "no"
280
281
if isPty {
@@ -283,6 +284,7 @@ func (s *Server) sessionStart(session ssh.Session, extraEnv []string) (retErr er
283
284
s .metrics .sessionErrors .WithLabelValues (magicTypeLabel , ptyLabel , "create_command" ).Add (1 )
284
285
return err
285
286
}
287
+ defer cleanup ()
286
288
287
289
if ssh .AgentRequested (session ) {
288
290
l , err := ssh .NewAgentListener ()
@@ -493,21 +495,21 @@ func (s *Server) sftpHandler(session ssh.Session) {
493
495
// CreateCommand processes raw command input with OpenSSH-like behavior.
494
496
// If the script provided is empty, it will default to the users shell.
495
497
// This injects environment variables specified by the user at launch too.
496
- func (s * Server ) CreateCommand (ctx context.Context , script string , env []string ) (* pty.Cmd , error ) {
498
+ func (s * Server ) CreateCommand (ctx context.Context , script string , env []string ) (* pty.Cmd , func (), error ) {
497
499
currentUser , err := user .Current ()
498
500
if err != nil {
499
- return nil , xerrors .Errorf ("get current user: %w" , err )
501
+ return nil , nil , xerrors .Errorf ("get current user: %w" , err )
500
502
}
501
503
username := currentUser .Username
502
504
503
505
shell , err := usershell .Get (username )
504
506
if err != nil {
505
- return nil , xerrors .Errorf ("get user shell: %w" , err )
507
+ return nil , nil , xerrors .Errorf ("get user shell: %w" , err )
506
508
}
507
509
508
510
manifest := s .Manifest .Load ()
509
511
if manifest == nil {
510
- return nil , xerrors .Errorf ("no metadata was provided" )
512
+ return nil , nil , xerrors .Errorf ("no metadata was provided" )
511
513
}
512
514
513
515
// OpenSSH executes all commands with the users current shell.
@@ -518,7 +520,9 @@ func (s *Server) CreateCommand(ctx context.Context, script string, env []string)
518
520
}
519
521
name := shell
520
522
args := []string {caller , script }
521
-
523
+ cleanup := func () {
524
+ // Default to noop. This only applies for scripts.
525
+ }
522
526
// A preceding space is generally not idiomatic for a shebang,
523
527
// but in Terraform it's quite standard to use <<EOF for a multi-line
524
528
// string which would indent with spaces, so we accept it for user-ease.
@@ -531,15 +535,31 @@ func (s *Server) CreateCommand(ctx context.Context, script string, env []string)
531
535
shebang = strings .TrimPrefix (shebang , "#!" )
532
536
words , err := shellquote .Split (shebang )
533
537
if err != nil {
534
- return nil , xerrors .Errorf ("split shebang: %w" , err )
538
+ return nil , nil , xerrors .Errorf ("split shebang: %w" , err )
535
539
}
536
540
name = words [0 ]
537
541
if len (words ) > 1 {
538
542
args = words [1 :]
539
543
} else {
540
544
args = []string {}
541
545
}
542
- args = append (args , caller , script )
546
+ scriptSha := sha256 .Sum256 ([]byte (script ))
547
+ tempFile , err := os .CreateTemp ("" , fmt .Sprintf ("coder-script-%x" , scriptSha ))
548
+ if err != nil {
549
+ return nil , nil , xerrors .Errorf ("create temp file: %w" , err )
550
+ }
551
+ cleanup = func () {
552
+ _ = os .Remove (tempFile .Name ())
553
+ }
554
+ _ , err = tempFile .WriteString (script )
555
+ if err != nil {
556
+ return nil , nil , xerrors .Errorf ("write temp file: %w" , err )
557
+ }
558
+ err = tempFile .Close ()
559
+ if err != nil {
560
+ return nil , nil , xerrors .Errorf ("close temp file: %w" , err )
561
+ }
562
+ args = append (args , tempFile .Name ())
543
563
}
544
564
545
565
// gliderlabs/ssh returns a command slice of zero
@@ -563,14 +583,14 @@ func (s *Server) CreateCommand(ctx context.Context, script string, env []string)
563
583
// Default to user home if a directory is not set.
564
584
homedir , err := userHomeDir ()
565
585
if err != nil {
566
- return nil , xerrors .Errorf ("get home dir: %w" , err )
586
+ return nil , nil , xerrors .Errorf ("get home dir: %w" , err )
567
587
}
568
588
cmd .Dir = homedir
569
589
}
570
590
cmd .Env = append (os .Environ (), env ... )
571
591
executablePath , err := os .Executable ()
572
592
if err != nil {
573
- return nil , xerrors .Errorf ("getting os executable: %w" , err )
593
+ return nil , nil , xerrors .Errorf ("getting os executable: %w" , err )
574
594
}
575
595
// Set environment variables reliable detection of being inside a
576
596
// Coder workspace.
@@ -615,7 +635,7 @@ func (s *Server) CreateCommand(ctx context.Context, script string, env []string)
615
635
cmd .Env = append (cmd .Env , fmt .Sprintf ("%s=%s" , envKey , value ))
616
636
}
617
637
618
- return cmd , nil
638
+ return cmd , cleanup , nil
619
639
}
620
640
621
641
func (s * Server ) Serve (l net.Listener ) (retErr error ) {
0 commit comments