Skip to content

Commit 50fb037

Browse files
committed
feat: --ssh-host-prefix flag for "coder ssh"
This adds a flag matching `--ssh-host-prefix` from `coder config-ssh` to `coder ssh`. By trimming a custom prefix from the argument, we can set up wildcard-based `Host` entries in SSH config for the IDE plugins (and eventually `coder config-ssh`). We also replace `--` in the argument with `/`, so ownership can be specified in wildcard-based SSH hosts like `<owner>--<workspace>`.
1 parent b67b88c commit 50fb037

File tree

4 files changed

+88
-1
lines changed

4 files changed

+88
-1
lines changed

cli/ssh.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ var (
6161
func (r *RootCmd) ssh() *serpent.Command {
6262
var (
6363
stdio bool
64+
hostPrefix string
6465
forwardAgent bool
6566
forwardGPG bool
6667
identityAgent string
@@ -195,7 +196,11 @@ func (r *RootCmd) ssh() *serpent.Command {
195196
parsedEnv = append(parsedEnv, [2]string{k, v})
196197
}
197198

198-
workspace, workspaceAgent, err := getWorkspaceAndAgent(ctx, inv, client, !disableAutostart, inv.Args[0])
199+
namedWorkspace := strings.TrimPrefix(inv.Args[0], hostPrefix)
200+
// Support "--" as a delimiter between owner and workspace name
201+
namedWorkspace = strings.ReplaceAll(namedWorkspace, "--", "/")
202+
203+
workspace, workspaceAgent, err := getWorkspaceAndAgent(ctx, inv, client, !disableAutostart, namedWorkspace)
199204
if err != nil {
200205
return err
201206
}
@@ -509,6 +514,12 @@ func (r *RootCmd) ssh() *serpent.Command {
509514
Description: "Specifies whether to emit SSH output over stdin/stdout.",
510515
Value: serpent.BoolOf(&stdio),
511516
},
517+
{
518+
Flag: "ssh-host-prefix",
519+
Env: "CODER_CONFIGSSH_SSH_HOST_PREFIX",
520+
Description: "Strip this prefix from the provided hostname to determine the workspace name.",
521+
Value: serpent.StringOf(&hostPrefix),
522+
},
512523
{
513524
Flag: "forward-agent",
514525
FlagShorthand: "A",

cli/ssh_test.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1555,6 +1555,69 @@ func TestSSH(t *testing.T) {
15551555
})
15561556
}
15571557
})
1558+
1559+
t.Run("SSHHostPrefix", func(t *testing.T) {
1560+
t.Parallel()
1561+
client, workspace, agentToken := setupWorkspaceForAgent(t)
1562+
_, _ = tGoContext(t, func(ctx context.Context) {
1563+
// Run this async so the SSH command has to wait for
1564+
// the build and agent to connect!
1565+
_ = agenttest.New(t, client.URL, agentToken)
1566+
<-ctx.Done()
1567+
})
1568+
1569+
clientOutput, clientInput := io.Pipe()
1570+
serverOutput, serverInput := io.Pipe()
1571+
defer func() {
1572+
for _, c := range []io.Closer{clientOutput, clientInput, serverOutput, serverInput} {
1573+
_ = c.Close()
1574+
}
1575+
}()
1576+
1577+
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
1578+
defer cancel()
1579+
1580+
user, err := client.User(ctx, codersdk.Me)
1581+
require.NoError(t, err)
1582+
1583+
inv, root := clitest.New(t, "ssh", "--stdio", "--ssh-host-prefix", "coder.dummy.com--", fmt.Sprintf("coder.dummy.com--%s--%s", user.Username, workspace.Name))
1584+
clitest.SetupConfig(t, client, root)
1585+
inv.Stdin = clientOutput
1586+
inv.Stdout = serverInput
1587+
inv.Stderr = io.Discard
1588+
1589+
cmdDone := tGo(t, func() {
1590+
err := inv.WithContext(ctx).Run()
1591+
assert.NoError(t, err)
1592+
})
1593+
1594+
conn, channels, requests, err := ssh.NewClientConn(&stdioConn{
1595+
Reader: serverOutput,
1596+
Writer: clientInput,
1597+
}, "", &ssh.ClientConfig{
1598+
// #nosec
1599+
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
1600+
})
1601+
require.NoError(t, err)
1602+
defer conn.Close()
1603+
1604+
sshClient := ssh.NewClient(conn, channels, requests)
1605+
session, err := sshClient.NewSession()
1606+
require.NoError(t, err)
1607+
defer session.Close()
1608+
1609+
command := "sh -c exit"
1610+
if runtime.GOOS == "windows" {
1611+
command = "cmd.exe /c exit"
1612+
}
1613+
err = session.Run(command)
1614+
require.NoError(t, err)
1615+
err = sshClient.Close()
1616+
require.NoError(t, err)
1617+
_ = clientOutput.Close()
1618+
1619+
<-cmdDone
1620+
})
15581621
}
15591622

15601623
//nolint:paralleltest // This test uses t.Setenv, parent test MUST NOT be parallel.

cli/testdata/coder_ssh_--help.golden

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ OPTIONS:
4545
-R, --remote-forward string-array, $CODER_SSH_REMOTE_FORWARD
4646
Enable remote port forwarding (remote_port:local_address:local_port).
4747

48+
--ssh-host-prefix string, $CODER_CONFIGSSH_SSH_HOST_PREFIX
49+
Strip this prefix from the provided hostname to determine the
50+
workspace name.
51+
4852
--stdio bool, $CODER_SSH_STDIO
4953
Specifies whether to emit SSH output over stdin/stdout.
5054

docs/reference/cli/ssh.md

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)