Skip to content

Commit

Permalink
fix(cli): add --devpod-home to ssh config (#1252)
Browse files Browse the repository at this point in the history
Users can specify a different location for the devpod directory other than
`~/.devpod` either by using the global flag `--devpod-home` or setting
the `DEVPOD_HOME` environment variable from DevPod Desktop or in their
shell.
This PR adds --devpod-home to the ssh config we generate after running
`devpod up ..` if it is set.
Because IDE's usually expect an ssh command, omitting the flag resulted
in non-functioning workspace.

Added another unit test for the ssh config
  • Loading branch information
pascalbreuninger authored Sep 13, 2024
1 parent 2b47efa commit 1d27dd7
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 98 deletions.
14 changes: 10 additions & 4 deletions cmd/up.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,9 +224,14 @@ func (cmd *UpCmd) Run(

// configure container ssh
if cmd.ConfigureSSH {
err = configureSSH(devPodConfig, client, cmd.SSHConfigPath, user, workdir,
cmd.GPGAgentForwarding ||
devPodConfig.ContextOption(config.ContextOptionGPGAgentForwarding) == "true")
devPodHome := ""
envDevPodHome, ok := os.LookupEnv("DEVPOD_HOME")
if ok {
devPodHome = envDevPodHome
}
setupGPGAgentForwarding := cmd.GPGAgentForwarding || devPodConfig.ContextOption(config.ContextOptionGPGAgentForwarding) == "true"

err = configureSSH(devPodConfig, client, cmd.SSHConfigPath, user, workdir, setupGPGAgentForwarding, devPodHome)
if err != nil {
return err
}
Expand Down Expand Up @@ -797,7 +802,7 @@ func startBrowserTunnel(
return nil
}

func configureSSH(c *config.Config, client client2.BaseWorkspaceClient, sshConfigPath, user, workdir string, gpgagent bool) error {
func configureSSH(c *config.Config, client client2.BaseWorkspaceClient, sshConfigPath, user, workdir string, gpgagent bool, devPodHome string) error {
path, err := devssh.ResolveSSHConfigPath(sshConfigPath)
if err != nil {
return errors.Wrap(err, "Invalid ssh config path")
Expand All @@ -811,6 +816,7 @@ func configureSSH(c *config.Config, client client2.BaseWorkspaceClient, sshConfi
user,
workdir,
gpgagent,
devPodHome,
log.Default,
)
if err != nil {
Expand Down
37 changes: 22 additions & 15 deletions pkg/ssh/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ var (
MarkerEndPrefix = "# DevPod End "
)

func ConfigureSSHConfig(sshConfigPath, context, workspace, user, workdir string, gpgagent bool, log log.Logger) error {
return configureSSHConfigSameFile(sshConfigPath, context, workspace, user, workdir, "", gpgagent, log)
func ConfigureSSHConfig(sshConfigPath, context, workspace, user, workdir string, gpgagent bool, devPodHome string, log log.Logger) error {
return configureSSHConfigSameFile(sshConfigPath, context, workspace, user, workdir, "", gpgagent, devPodHome, log)
}

func configureSSHConfigSameFile(sshConfigPath, context, workspace, user, workdir, command string, gpgagent bool, log log.Logger) error {
func configureSSHConfigSameFile(sshConfigPath, context, workspace, user, workdir, command string, gpgagent bool, devPodHome string, log log.Logger) error {
configLock.Lock()
defer configLock.Unlock()

newFile, err := addHost(sshConfigPath, workspace+"."+"devpod", user, context, workspace, workdir, command, gpgagent)
newFile, err := addHost(sshConfigPath, workspace+"."+"devpod", user, context, workspace, workdir, command, gpgagent, devPodHome)
if err != nil {
return errors.Wrap(err, "parse ssh config")
}
Expand All @@ -46,7 +46,7 @@ type DevPodSSHEntry struct {
Workspace string
}

func addHost(path, host, user, context, workspace, workdir, command string, gpgagent bool) (string, error) {
func addHost(path, host, user, context, workspace, workdir, command string, gpgagent bool, devPodHome string) (string, error) {
newConfig, err := removeFromConfig(path, host)
if err != nil {
return "", err
Expand All @@ -58,10 +58,10 @@ func addHost(path, host, user, context, workspace, workdir, command string, gpga
return "", err
}

return addHostSection(newConfig, execPath, host, user, context, workspace, workdir, command, gpgagent)
return addHostSection(newConfig, execPath, host, user, context, workspace, workdir, command, gpgagent, devPodHome)
}

func addHostSection(config, execPath, host, user, context, workspace, workdir, command string, gpgagent bool) (string, error) {
func addHostSection(config, execPath, host, user, context, workspace, workdir, command string, gpgagent bool, devPodHome string) (string, error) {
newLines := []string{}
// add new section
startMarker := MarkerStartPrefix + host
Expand All @@ -73,17 +73,24 @@ func addHostSection(config, execPath, host, user, context, workspace, workdir, c
newLines = append(newLines, " StrictHostKeyChecking no")
newLines = append(newLines, " UserKnownHostsFile /dev/null")
newLines = append(newLines, " HostKeyAlgorithms rsa-sha2-256,rsa-sha2-512,ssh-rsa")

proxyCommand := ""
if command != "" {
newLines = append(newLines, fmt.Sprintf(" ProxyCommand \"%s\"", command))
} else if gpgagent {
newLines = append(newLines, fmt.Sprintf(" ProxyCommand \"%s\" ssh --gpg-agent-forwarding --stdio --context %s --user %s %s", execPath, context, user, workspace))
proxyCommand = fmt.Sprintf(" ProxyCommand \"%s\"", command)
} else {
proxyCommand := fmt.Sprintf(" ProxyCommand \"%s\" ssh --stdio --context %s --user %s %s", execPath, context, user, workspace)
if workdir != "" {
proxyCommand = fmt.Sprintf("%s --workdir %s", proxyCommand, workdir)
}
newLines = append(newLines, proxyCommand)
proxyCommand = fmt.Sprintf(" ProxyCommand \"%s\" ssh --stdio --context %s --user %s %s", execPath, context, user, workspace)
}

if devPodHome != "" {
proxyCommand = fmt.Sprintf("%s --devpod-home \"%s\"", proxyCommand, devPodHome)
}
if workdir != "" {
proxyCommand = fmt.Sprintf("%s --workdir \"%s\"", proxyCommand, workdir)
}
if gpgagent {
proxyCommand = fmt.Sprintf("%s --gpg-agent-forwarding", proxyCommand)
}
newLines = append(newLines, proxyCommand)
newLines = append(newLines, " User "+user)
newLines = append(newLines, endMarker)

Expand Down
189 changes: 110 additions & 79 deletions pkg/ssh/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,31 @@ import (

func TestAddHostSection(t *testing.T) {
tests := []struct {
name string
config string
execPath string
host string
user string
context string
workspace string
workdir string
command string
gpgagent bool
expected string
name string
config string
execPath string
host string
user string
context string
workspace string
workdir string
command string
gpgagent bool
devPodHome string
expected string
}{
{
name: "Basic host addition",
config: "",
execPath: "/path/to/exec",
host: "testhost",
user: "testuser",
context: "testcontext",
workspace: "testworkspace",
workdir: "",
command: "",
gpgagent: false,
name: "Basic host addition",
config: "",
execPath: "/path/to/exec",
host: "testhost",
user: "testuser",
context: "testcontext",
workspace: "testworkspace",
workdir: "",
command: "",
gpgagent: false,
devPodHome: "",
expected: `# DevPod Start testhost
Host testhost
ForwardAgent yes
Expand All @@ -45,60 +47,86 @@ Host testhost
# DevPod End testhost`,
},
{
name: "Host addition with workdir",
config: "",
execPath: "/path/to/exec",
host: "testhost",
user: "testuser",
context: "testcontext",
workspace: "testworkspace",
workdir: "/path/to/workdir",
command: "",
gpgagent: false,
name: "Basic host addition with DEVPOD_HOME",
config: "",
execPath: "/path/to/exec",
host: "testhost",
user: "testuser",
context: "testcontext",
workspace: "testworkspace",
workdir: "",
command: "",
gpgagent: false,
devPodHome: "C:\\\\White Space\\devpod\\test",
expected: `# DevPod Start testhost
Host testhost
ForwardAgent yes
LogLevel error
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
HostKeyAlgorithms rsa-sha2-256,rsa-sha2-512,ssh-rsa
ProxyCommand "/path/to/exec" ssh --stdio --context testcontext --user testuser testworkspace --workdir /path/to/workdir
ProxyCommand "/path/to/exec" ssh --stdio --context testcontext --user testuser testworkspace --devpod-home "C:\\White Space\devpod\test"
User testuser
# DevPod End testhost`,
},
{
name: "Host addition with gpg agent",
config: "",
execPath: "/path/to/exec",
host: "testhost",
user: "testuser",
context: "testcontext",
workspace: "testworkspace",
workdir: "",
command: "",
gpgagent: true,
name: "Host addition with workdir",
config: "",
execPath: "/path/to/exec",
host: "testhost",
user: "testuser",
context: "testcontext",
workspace: "testworkspace",
workdir: "/path/to/workdir",
command: "",
gpgagent: false,
devPodHome: "",
expected: `# DevPod Start testhost
Host testhost
ForwardAgent yes
LogLevel error
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
HostKeyAlgorithms rsa-sha2-256,rsa-sha2-512,ssh-rsa
ProxyCommand "/path/to/exec" ssh --gpg-agent-forwarding --stdio --context testcontext --user testuser testworkspace
ProxyCommand "/path/to/exec" ssh --stdio --context testcontext --user testuser testworkspace --workdir "/path/to/workdir"
User testuser
# DevPod End testhost`,
},
{
name: "Host addition with custom command",
config: "",
execPath: "/path/to/exec",
host: "testhost",
user: "testuser",
context: "testcontext",
workspace: "testworkspace",
workdir: "",
command: "ssh -W %h:%p bastion",
gpgagent: false,
name: "Host addition with gpg agent",
config: "",
execPath: "/path/to/exec",
host: "testhost",
user: "testuser",
context: "testcontext",
workspace: "testworkspace",
workdir: "",
command: "",
gpgagent: true,
devPodHome: "",
expected: `# DevPod Start testhost
Host testhost
ForwardAgent yes
LogLevel error
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
HostKeyAlgorithms rsa-sha2-256,rsa-sha2-512,ssh-rsa
ProxyCommand "/path/to/exec" ssh --stdio --context testcontext --user testuser testworkspace --gpg-agent-forwarding
User testuser
# DevPod End testhost`,
},
{
name: "Host addition with custom command",
config: "",
execPath: "/path/to/exec",
host: "testhost",
user: "testuser",
context: "testcontext",
workspace: "testworkspace",
workdir: "",
command: "ssh -W %h:%p bastion",
gpgagent: false,
devPodHome: "",
expected: `# DevPod Start testhost
Host testhost
ForwardAgent yes
Expand All @@ -114,14 +142,15 @@ Host testhost
name: "Host addition to existing config",
config: `Host existinghost
User existinguser`,
execPath: "/path/to/exec",
host: "testhost",
user: "testuser",
context: "testcontext",
workspace: "testworkspace",
workdir: "",
command: "",
gpgagent: false,
execPath: "/path/to/exec",
host: "testhost",
user: "testuser",
context: "testcontext",
workspace: "testworkspace",
workdir: "",
command: "",
gpgagent: false,
devPodHome: "",
expected: `# DevPod Start testhost
Host testhost
ForwardAgent yes
Expand Down Expand Up @@ -150,14 +179,15 @@ Host existingtesthost
Host existinghost
User existinguser`,
execPath: "/path/to/exec",
host: "testhost",
user: "testuser",
context: "testcontext",
workspace: "testworkspace",
workdir: "",
command: "",
gpgagent: false,
execPath: "/path/to/exec",
host: "testhost",
user: "testuser",
context: "testcontext",
workspace: "testworkspace",
workdir: "",
command: "",
gpgagent: false,
devPodHome: "",
expected: `# DevPod Start testhost
Host testhost
ForwardAgent yes
Expand Down Expand Up @@ -191,14 +221,15 @@ Include ~/config2
Include ~/config3`,
execPath: "/path/to/exec",
host: "testhost",
user: "testuser",
context: "testcontext",
workspace: "testworkspace",
workdir: "",
command: "",
gpgagent: false,
execPath: "/path/to/exec",
host: "testhost",
user: "testuser",
context: "testcontext",
workspace: "testworkspace",
workdir: "",
command: "",
gpgagent: false,
devPodHome: "",
expected: `Include ~/config1
Include ~/config2
Expand All @@ -221,7 +252,7 @@ Host testhost

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := addHostSection(tt.config, tt.execPath, tt.host, tt.user, tt.context, tt.workspace, tt.workdir, tt.command, tt.gpgagent)
result, err := addHostSection(tt.config, tt.execPath, tt.host, tt.user, tt.context, tt.workspace, tt.workdir, tt.command, tt.gpgagent, tt.devPodHome)
if err != nil {
t.Errorf("Failed with err: %v", err)
}
Expand All @@ -247,7 +278,7 @@ Host testhost
t.Errorf("Result does not contain the custom ProxyCommand: %s", tt.command)
}

if tt.workdir != "" && !strings.Contains(result, "--workdir "+tt.workdir) {
if tt.workdir != "" && !strings.Contains(result, fmt.Sprintf("--workdir \"%s\"", tt.workdir)) {
t.Errorf("Result does not contain the workdir: %s", tt.workdir)
}

Expand Down

0 comments on commit 1d27dd7

Please sign in to comment.