8000 ssh: explicitly set ~ for home directory unless using cmd.exe by spikecurtis · Pull Request #1 · coder/mutagen · GitHub
[go: up one dir, main page]

Skip to content

ssh: explicitly set ~ for home directory unless using cmd.exe #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Mar 17, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
ssh: add tests for explicit ~
  • Loading branch information
spikecurtis committed Mar 7, 2025
commit 36d4929f47730ccb5d68b305319489f59ccc926f
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# Build output
/build/
.idea/
89 changes: 45 additions & 44 deletions pkg/agent/dial.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
"errors"
"fmt"
"github.com/mutagen-io/mutagen/pkg/prompting"
"io"
"strings"
"time"
Expand All @@ -14,7 +15,6 @@ import (
"github.com/mutagen-io/mutagen/pkg/logging"
"github.com/mutagen-io/mutagen/pkg/mutagen"
"github.com/mutagen-io/mutagen/pkg/platform/terminal"
"github.com/mutagen-io/mutagen/pkg/prompting"
streampkg "github.com/mutagen-io/mutagen/pkg/stream"
)

Expand All @@ -34,49 +34,7 @@ const (
// installation should be attempted and whether or not the remote environment is
// cmd.exe-based.
func connect(logger *logging.Logger, transport Transport, mode, prompter string, cmdExe bool) (io.ReadWriteCloser, bool, bool, error) {
// Compute the agent invocation command, relative to the user's home
// directory on the remote. Unless we have reason to assume that this is a
// cmd.exe environment, we construct a path using forward slashes. This will
// work for all POSIX systems and POSIX-like environments on Windows. If we
// know we're hitting a cmd.exe environment, then we use backslashes,
// otherwise the invocation won't work. Watching for cmd.exe to fail on
// commands with forward slashes is actually the way that we detect cmd.exe
// environments.
//
// HACK: We're assuming that none of these path components have spaces in
// them, but since we control all of them, this is probably okay.
//
// HACK: When invoking on Windows systems (whether inside a POSIX
// environment or cmd.exe), we can leave the "exe" suffix off the target
// name. Fortunately this allows us to also avoid having to try the
// combination of forward slashes + ".exe" for Windows POSIX environments.
//
// HACK: When invoking on cmd.exe, we leave off the ~ prefix, since cmd.exe
// doesn't recognize it. In most cases the initial working directory for SSH
// commands is the home directory, but when possible we try to be explicit,
// to work around systems that use a different directory, such as Coder
// workspaces, which allow different initial working directories to be
// configured.
pathSeparator := "/"
pathComponents := []string{filesystem.HomeDirectorySpecial}
if cmdExe {
pathSeparator = "\\"
pathComponents = nil
}
dataDirectoryName := filesystem.MutagenDataDirectoryName
if mutagen.DevelopmentModeEnabled {
dataDirectoryName = filesystem.MutagenDataDirectoryDevelopmentName
}
pathComponents = append(pathComponents,
dataDirectoryName,
filesystem.MutagenAgentsDirectoryName,
mutagen.Version,
BaseName,
)
agentInvocationPath := strings.Join(pathComponents, pathSeparator)

// Compute the command to invoke.
command := fmt.Sprintf("%s %s --%s=%s", agentInvocationPath, mode, FlagLogLevel, logger.Level())
command := fmt.Sprintf("%s %s --%s=%s", agentInvocationPath(cmdExe), mode, FlagLogLevel, logger.Level())

// Set up (but do not start) an agent process.
message := "Connecting to agent (POSIX)..."
Expand Down Expand Up @@ -186,6 +144,49 @@ func connect(logger *logging.Logger, transport Transport, mode, prompter string,
return stream, false, false, nil
}

// agentInvocationPath computes the agent invocation path, relative to the user's home
// directory on the remote.
func agentInvocationPath(cmdExe bool) string {
// Unless we have reason to assume that this is a cmd.exe environment, we
// construct a path using forward slashes. This will work for all POSIX
// systems and POSIX-like environments on Windows. If we know we're hitting
// a cmd.exe environment, then we use backslashes, otherwise the invocation
// won't work. Watching for cmd.exe to fail on commands with forward slashes
// is actually the way that we detect cmd.exe environments.
//
// HACK: We're assuming that none of these path components have spaces in
// them, but since we control all of them, this is probably okay.
//
// HACK: When invoking on Windows systems (whether inside a POSIX
// environment or cmd.exe), we can leave the "exe" suffix off the target
// name. Fortunately this allows us to also avoid having to try the
// combination of forward slashes + ".exe" for Windows POSIX environments.
//
// HACK: When invoking on cmd.exe, we leave off the ~ prefix, since cmd.exe
// doesn't recognize it. In most cases the initial working directory for SSH
// commands is the home directory, but when possible we try to be explicit,
// to work around systems that use a different directory, such as Coder
// workspaces, which allow different initial working directories to be
// configured.
pathSeparator := "/"
pathComponents := []string{filesystem.HomeDirectorySpecial}
if cmdExe {
pathSeparator = "\\"
pathComponents = nil
}
dataDirectoryName := filesystem.MutagenDataDirectoryName
if mutagen.DevelopmentModeEnabled {
dataDirectoryName = filesystem.MutagenDataDirectoryDevelopmentName
}
pathComponents = append(pathComponents,
dataDirectoryName,
filesystem.MutagenAgentsDirectoryName,
mutagen.Version,
BaseName,
)
return strings.Join(pathComponents, pathSeparator)
}

// Dial connects to an agent-based endpoint using the specified transport,
// connection mode, and prompter.
func Dial(logger *logging.Logger, transport Transport, mode, prompter string) (io.ReadWriteCloser, error) {
Expand Down
20 changes: 19 additions & 1 deletion pkg/agent/dial_test.go
8000
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
package agent

// TODO: Implement.
import (
"fmt"
"github.com/mutagen-io/mutagen/pkg/mutagen"
"testing"
)

func TestAgentInvocationPath(t *testing.T) {
path := agentInvocationPath(false)
expected := fmt.Sprintf("~/.mutagen/agents/%s/mutagen-agent", mutagen.Version)
if path != expected {
t.Errorf("Invocation path cmdExe=false, expected %s, got %s", expected, path)
}

path = agentInvocationPath(true)
expected = fmt.Sprintf(".mutagen\\agents\\%s\\mutagen-agent", mutagen.Version)
if path != expected {
t.Errorf("Invocation path cmdExe=true, expected %s, got %s", expected, path)
}
}
8 changes: 1 addition & 7 deletions pkg/agent/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,13 +111,7 @@ func install(logger *logging.Logger, transport Transport, prompter string, cmdEx
if err := prompting.Message(prompter, "Installing agent..."); err != nil {
return fmt.Errorf("unable to message prompter: %w", err)
}
var installCommand string
if posix && cmdExe {
// TODO: is this path even possible?
installCommand = fmt.Sprintf("./%s %s", fullRemotePath, CommandInstall)
} else {
installCommand = fmt.Sprintf("%s %s", fullRemotePath, CommandInstall)
}
installCommand := fmt.Sprintf("%s %s", fullRemotePath, CommandInstall)
if err := run(transport, installCommand); err != nil {
return fmt.Errorf("unable to invoke agent installation: %w", err)
}
Expand Down
Loading
0