diff --git a/cli/configssh.go b/cli/configssh.go index f40fe484536b3..162c3c2a95855 100644 --- a/cli/configssh.go +++ b/cli/configssh.go @@ -198,6 +198,7 @@ func (r *RootCmd) configSSH() *clibase.Cmd { dryRun bool skipProxyCommand bool forceUnixSeparators bool + coderCliPath string ) client := new(codersdk.Client) cmd := &clibase.Cmd{ @@ -233,10 +234,16 @@ func (r *RootCmd) configSSH() *clibase.Cmd { // that it's possible to capture the diff. out = inv.Stderr } - coderBinary, err := currentBinPath(out) - if err != nil { - return err + + var err error + coderBinary := coderCliPath + if coderBinary == "" { + coderBinary, err = currentBinPath(out) + if err != nil { + return err + } } + escapedCoderBinary, err := sshConfigExecEscape(coderBinary, forceUnixSeparators) if err != nil { return xerrors.Errorf("escape coder binary for ssh failed: %w", err) @@ -501,6 +508,24 @@ func (r *RootCmd) configSSH() *clibase.Cmd { Description: "Specifies the path to an SSH config.", Value: clibase.StringOf(&sshConfigFile), }, + { + Flag: "coder-binary-path", + Env: "CODER_SSH_CONFIG_BINARY_PATH", + Default: "", + Description: "Optionally specify the absolute path to the coder binary used in ProxyCommand. " + + "By default, the binary invoking this command ('config ssh') is used.", + Value: clibase.Validate(clibase.StringOf(&coderCliPath), func(value *clibase.String) error { + if runtime.GOOS == goosWindows { + // For some reason filepath.IsAbs() does not work on windows. + return nil + } + absolute := filepath.IsAbs(value.String()) + if !absolute { + return xerrors.Errorf("coder cli path must be an absolute path") + } + return nil + }), + }, { Flag: "ssh-option", FlagShorthand: "o", diff --git a/cli/configssh_test.go b/cli/configssh_test.go index f502304373f80..34da7dd03fcc0 100644 --- a/cli/configssh_test.go +++ b/cli/configssh_test.go @@ -216,18 +216,20 @@ func TestConfigSSH_FileWriteAndOptionsFlow(t *testing.T) { ssh string } type wantConfig struct { - ssh string + ssh string + regexMatch string } type match struct { match, write string } tests := []struct { - name string - args []string - matches []match - writeConfig writeConfig - wantConfig wantConfig - wantErr bool + name string + args []string + matches []match + writeConfig writeConfig + wantConfig wantConfig + wantErr bool + echoResponse *echo.Responses }{ { name: "Config file is created", @@ -579,6 +581,20 @@ func TestConfigSSH_FileWriteAndOptionsFlow(t *testing.T) { }, wantErr: true, }, + { + name: "Custom CLI Path", + args: []string{ + "-y", "--coder-binary-path", "/foo/bar/coder", + }, + wantErr: false, + echoResponse: &echo.Responses{ + Parse: echo.ParseComplete, + ProvisionApply: echo.ProvisionApplyWithAgent(""), + }, + wantConfig: wantConfig{ + regexMatch: "ProxyCommand /foo/bar/coder", + }, + }, } for _, tt := range tests { tt := tt @@ -588,7 +604,7 @@ func TestConfigSSH_FileWriteAndOptionsFlow(t *testing.T) { var ( client = coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) user = coderdtest.CreateFirstUser(t, client) - version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) + version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, tt.echoResponse) _ = coderdtest.AwaitTemplateVersionJob(t, client, version.ID) project = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) workspace = coderdtest.CreateWorkspace(t, client, user.OrganizationID, project.ID) @@ -627,9 +643,14 @@ func TestConfigSSH_FileWriteAndOptionsFlow(t *testing.T) { <-done - if tt.wantConfig.ssh != "" { + if tt.wantConfig.ssh != "" || tt.wantConfig.regexMatch != "" { got := sshConfigFileRead(t, sshConfigName) - assert.Equal(t, tt.wantConfig.ssh, got) + if tt.wantConfig.ssh != "" { + assert.Equal(t, tt.wantConfig.ssh, got) + } + if tt.wantConfig.regexMatch != "" { + assert.Regexp(t, tt.wantConfig.regexMatch, got, "regex match") + } } }) } diff --git a/cli/testdata/coder_config-ssh_--help.golden b/cli/testdata/coder_config-ssh_--help.golden index 857962b27141b..8aa547ccb467f 100644 --- a/cli/testdata/coder_config-ssh_--help.golden +++ b/cli/testdata/coder_config-ssh_--help.golden @@ -12,6 +12,11 @@ Add an SSH Host entry for your workspaces "ssh coder.workspace"  $ coder config-ssh --dry-run  Options + --coder-binary-path string, $CODER_SSH_CONFIG_BINARY_PATH + Optionally specify the absolute path to the coder binary used in + ProxyCommand. By default, the binary invoking this command ('config + ssh') is used. + -n, --dry-run bool, $CODER_SSH_DRY_RUN Perform a trial run with no changes made, showing a diff at the end. diff --git a/docs/cli/config-ssh.md b/docs/cli/config-ssh.md index 6178e207e1d30..9d5196c824827 100644 --- a/docs/cli/config-ssh.md +++ b/docs/cli/config-ssh.md @@ -25,6 +25,15 @@ coder config-ssh [flags] ## Options +### --coder-binary-path + +| | | +| ----------- | ------------------------------------------ | +| Type | string | +| Environment | $CODER_SSH_CONFIG_BINARY_PATH | + +Optionally specify the absolute path to the coder binary used in ProxyCommand. By default, the binary invoking this command ('config ssh') is used. + ### -n, --dry-run | | |