@@ -698,63 +698,24 @@ func (s *Server) sftpHandler(logger slog.Logger, session ssh.Session) {
698
698
_ = session .Exit (1 )
699
699
}
700
700
701
- // EnvInfoer encapsulates external information required by CreateCommand.
702
- type EnvInfoer interface {
703
- // CurrentUser returns the current user.
704
- CurrentUser () (* user.User , error )
705
- // Environ returns the environment variables of the current process.
706
- Environ () []string
707
- // UserHomeDir returns the home directory of the current user.
708
- UserHomeDir () (string , error )
709
- // UserShell returns the shell of the given user.
710
- UserShell (username string ) (string , error )
711
- }
712
-
713
- type systemEnvInfoer struct {}
714
-
715
- var defaultEnvInfoer EnvInfoer = & systemEnvInfoer {}
716
-
717
- // DefaultEnvInfoer returns a default implementation of
718
- // EnvInfoer. This reads information using the default Go
719
- // implementations.
720
- func DefaultEnvInfoer () EnvInfoer {
721
- return defaultEnvInfoer
722
- }
723
-
724
- func (systemEnvInfoer ) CurrentUser () (* user.User , error ) {
725
- return user .Current ()
726
- }
727
-
728
- func (systemEnvInfoer ) Environ () []string {
729
- return os .Environ ()
730
- }
731
-
732
- func (systemEnvInfoer ) UserHomeDir () (string , error ) {
733
- return userHomeDir ()
734
- }
735
-
736
- func (systemEnvInfoer ) UserShell (username string ) (string , error ) {
737
- return usershell .Get (username )
738
- }
739
-
740
701
// CreateCommand processes raw command input with OpenSSH-like behavior.
741
702
// If the script provided is empty, it will default to the users shell.
742
703
// This injects environment variables specified by the user at launch too.
743
704
// The final argument is an interface that allows the caller to provide
744
705
// alternative implementations for the dependencies of CreateCommand.
745
706
// This is useful when creating a command to be run in a separate environment
746
707
// (for example, a Docker container). Pass in nil to use the default.
747
- func (s * Server ) CreateCommand (ctx context.Context , script string , env []string , deps EnvInfoer ) (* pty.Cmd , error ) {
748
- if deps == nil {
749
- deps = DefaultEnvInfoer ()
708
+ func (s * Server ) CreateCommand (ctx context.Context , script string , env []string , ei usershell. EnvInfoer ) (* pty.Cmd , error ) {
709
+ if ei == nil {
710
+ ei = & usershell. SystemEnvInfo {}
750
711
}
751
- currentUser , err := deps . CurrentUser ()
712
+ currentUser , err := ei . User ()
752
713
if err != nil {
753
714
return nil , xerrors .Errorf ("get current user: %w" , err )
754
715
}
755
716
username := currentUser .Username
756
717
757
- shell , err := deps . UserShell (username )
718
+ shell , err := ei . Shell (username )
758
719
if err != nil {
759
720
return nil , xerrors .Errorf ("get user shell: %w" , err )
760
721
}
@@ -802,21 +763,32 @@ func (s *Server) CreateCommand(ctx context.Context, script string, env []string,
802
763
}
803
764
}
804
765
805
- cmd := s .Execer .PTYCommandContext (ctx , name , args ... )
766
+ // Modify command prior to execution. This will usually be a no-op, but not
767
+ // always. For example, to run a command in a Docker container, we need to
768
+ // modify the command to be `docker exec -it <container> <command>`.
769
+ modifiedName , modifiedArgs := ei .ModifyCommand (name , args ... )
770
+ // Log if the command was modified.
771
+ if modifiedName != name && slices .Compare (modifiedArgs , args ) != 0 {
772
+ s .logger .Debug (ctx , "modified command" ,
773
+ slog .F ("before" , append ([]string {name }, args ... )),
774
+ slog .F ("after" , append ([]string {modifiedName }, modifiedArgs ... )),
775
+ )
776
+ }
777
+ cmd := s .Execer .PTYCommandContext (ctx , modifiedName , modifiedArgs ... )
806
778
cmd .Dir = s .config .WorkingDirectory ()
807
779
808
780
// If the metadata directory doesn't exist, we run the command
809
781
// in the users home directory.
810
782
_ , err = os .Stat (cmd .Dir )
811
783
if cmd .Dir == "" || err != nil {
812
784
// Default to user home if a directory is not set.
813
- homedir , err := deps . UserHomeDir ()
785
+ homedir , err := ei . HomeDir ()
814
786
if err != nil {
815
787
return nil , xerrors .Errorf ("get home dir: %w" , err )
816
788
}
817
789
cmd .Dir = homedir
818
790
}
819
- cmd .Env = append (deps .Environ (), env ... )
791
+ cmd .Env = append (ei .Environ (), env ... )
820
792
cmd .Env = append (cmd .Env , fmt .Sprintf ("USER=%s" , username ))
821
793
822
794
// Set SSH connection environment variables (these are also set by OpenSSH
0 commit comments