Skip to content

Commit 6bea82b

Browse files
authored
fix(agent/agentssh)!: use configured directory for SFTP connections (#21194)
BREAKING CHANGE: SFTP/SCP now respects the agent's configured directory. If your workspace agent has a custom `dir` configured in Terraform, SFTP and SCP connections will now land there instead of `$HOME`. Previously, only SSH and rsync respected this setting, which caused confusing behavior where `scp file.txt coder:.` and `rsync file.txt coder:.` would put files in different places. If you have scripts that relied on SFTP/SCP always using `$HOME` regardless of agent configuration, you may need to use explicit paths instead.
1 parent e740872 commit 6bea82b

File tree

2 files changed

+83
-42
lines changed

2 files changed

+83
-42
lines changed

agent/agent_test.go

Lines changed: 70 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -994,42 +994,77 @@ func TestAgent_UnixRemoteForwarding(t *testing.T) {
994994

995995
func TestAgent_SFTP(t *testing.T) {
996996
t.Parallel()
997-
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
998-
defer cancel()
999-
u, err := user.Current()
1000-
require.NoError(t, err, "get current user")
1001-
home := u.HomeDir
1002-
if runtime.GOOS == "windows" {
1003-
home = "/" + strings.ReplaceAll(home, "\\", "/")
1004-
}
1005-
//nolint:dogsled
1006-
conn, agentClient, _, _, _ := setupAgent(t, agentsdk.Manifest{}, 0)
1007-
sshClient, err := conn.SSHClient(ctx)
1008-
require.NoError(t, err)
1009-
defer sshClient.Close()
1010-
client, err := sftp.NewClient(sshClient)
1011-
require.NoError(t, err)
1012-
defer client.Close()
1013-
wd, err := client.Getwd()
1014-
require.NoError(t, err, "get working directory")
1015-
require.Equal(t, home, wd, "working directory should be home user home")
1016-
tempFile := filepath.Join(t.TempDir(), "sftp")
1017-
// SFTP only accepts unix-y paths.
1018-
remoteFile := filepath.ToSlash(tempFile)
1019-
if !path.IsAbs(remoteFile) {
1020-
// On Windows, e.g. "/C:/Users/...".
1021-
remoteFile = path.Join("/", remoteFile)
1022-
}
1023-
file, err := client.Create(remoteFile)
1024-
require.NoError(t, err)
1025-
err = file.Close()
1026-
require.NoError(t, err)
1027-
_, err = os.Stat(tempFile)
1028-
require.NoError(t, err)
1029997

1030-
// Close the client to trigger disconnect event.
1031-
_ = client.Close()
1032-
assertConnectionReport(t, agentClient, proto.Connection_SSH, 0, "")
998+
t.Run("DefaultWorkingDirectory", func(t *testing.T) {
999+
t.Parallel()
1000+
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
1001+
defer cancel()
1002+
u, err := user.Current()
1003+
require.NoError(t, err, "get current user")
1004+
home := u.HomeDir
1005+
if runtime.GOOS == "windows" {
1006+
home = "/" + strings.ReplaceAll(home, "\\", "/")
1007+
}
1008+
//nolint:dogsled
1009+
conn, agentClient, _, _, _ := setupAgent(t, agentsdk.Manifest{}, 0)
1010+
sshClient, err := conn.SSHClient(ctx)
1011+
require.NoError(t, err)
1012+
defer sshClient.Close()
1013+
client, err := sftp.NewClient(sshClient)
1014+
require.NoError(t, err)
1015+
defer client.Close()
1016+
wd, err := client.Getwd()
1017+
require.NoError(t, err, "get working directory")
1018+
require.Equal(t, home, wd, "working directory should be user home")
1019+
tempFile := filepath.Join(t.TempDir(), "sftp")
1020+
// SFTP only accepts unix-y paths.
1021+
remoteFile := filepath.ToSlash(tempFile)
1022+
if !path.IsAbs(remoteFile) {
1023+
// On Windows, e.g. "/C:/Users/...".
1024+
remoteFile = path.Join("/", remoteFile)
1025+
}
1026+
file, err := client.Create(remoteFile)
1027+
require.NoError(t, err)
1028+
err = file.Close()
1029+
require.NoError(t, err)
1030+
_, err = os.Stat(tempFile)
1031+
require.NoError(t, err)
1032+
1033+
// Close the client to trigger disconnect event.
1034+
_ = client.Close()
1035+
assertConnectionReport(t, agentClient, proto.Connection_SSH, 0, "")
1036+
})
1037+
1038+
t.Run("CustomWorkingDirectory", func(t *testing.T) {
1039+
t.Parallel()
1040+
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
1041+
defer cancel()
1042+
1043+
// Create a custom directory for the agent to use.
1044+
customDir := t.TempDir()
1045+
expectedDir := customDir
1046+
if runtime.GOOS == "windows" {
1047+
expectedDir = "/" + strings.ReplaceAll(customDir, "\\", "/")
1048+
}
1049+
1050+
//nolint:dogsled
1051+
conn, agentClient, _, _, _ := setupAgent(t, agentsdk.Manifest{
1052+
Directory: customDir,
1053+
}, 0)
1054+
sshClient, err := conn.SSHClient(ctx)
1055+
require.NoError(t, err)
1056+
defer sshClient.Close()
1057+
client, err := sftp.NewClient(sshClient)
1058+
require.NoError(t, err)
1059+
defer client.Close()
1060+
wd, err := client.Getwd()
1061+
require.NoError(t, err, "get working directory")
1062+
require.Equal(t, expectedDir, wd, "working directory should be custom directory")
1063+
1064+
// Close the client to trigger disconnect event.
1065+
_ = client.Close()
1066+
assertConnectionReport(t, agentClient, proto.Connection_SSH, 0, "")
1067+
})
10331068
}
10341069

10351070
func TestAgent_SCP(t *testing.T) {

agent/agentssh/agentssh.go

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -829,13 +829,19 @@ func (s *Server) sftpHandler(logger slog.Logger, session ssh.Session) error {
829829
session.DisablePTYEmulation()
830830

831831
var opts []sftp.ServerOption
832-
// Change current working directory to the users home
833-
// directory so that SFTP connections land there.
834-
homedir, err := userHomeDir()
835-
if err != nil {
836-
logger.Warn(ctx, "get sftp working directory failed, unable to get home dir", slog.Error(err))
837-
} else {
838-
opts = append(opts, sftp.WithServerWorkingDirectory(homedir))
832+
// Change current working directory to the configured
833+
// directory (or home directory if not set) so that SFTP
834+
// connections land there.
835+
dir := s.config.WorkingDirectory()
836+
if dir == "" {
837+
var err error
838+
dir, err = userHomeDir()
839+
if err != nil {
840+
logger.Warn(ctx, "get sftp working directory failed, unable to get home dir", slog.Error(err))
841+
}
842+
}
843+
if dir != "" {
844+
opts = append(opts, sftp.WithServerWorkingDirectory(dir))
839845
}
840846

841847
server, err := sftp.NewServer(session, opts...)

0 commit comments

Comments
 (0)