mirror of
https://github.com/coder/coder.git
synced 2025-07-12 00:14:10 +00:00
feat: add --ssh-host-prefix flag for "coder ssh" (#16088)
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>`. Replaces #16087. Part of https://github.com/coder/coder/issues/14986. Related to https://github.com/coder/coder/pull/16078 and https://github.com/coder/coder/pull/16080.
This commit is contained in:
13
cli/ssh.go
13
cli/ssh.go
@ -61,6 +61,7 @@ var (
|
|||||||
func (r *RootCmd) ssh() *serpent.Command {
|
func (r *RootCmd) ssh() *serpent.Command {
|
||||||
var (
|
var (
|
||||||
stdio bool
|
stdio bool
|
||||||
|
hostPrefix string
|
||||||
forwardAgent bool
|
forwardAgent bool
|
||||||
forwardGPG bool
|
forwardGPG bool
|
||||||
identityAgent string
|
identityAgent string
|
||||||
@ -195,7 +196,11 @@ func (r *RootCmd) ssh() *serpent.Command {
|
|||||||
parsedEnv = append(parsedEnv, [2]string{k, v})
|
parsedEnv = append(parsedEnv, [2]string{k, v})
|
||||||
}
|
}
|
||||||
|
|
||||||
workspace, workspaceAgent, err := getWorkspaceAndAgent(ctx, inv, client, !disableAutostart, inv.Args[0])
|
namedWorkspace := strings.TrimPrefix(inv.Args[0], hostPrefix)
|
||||||
|
// Support "--" as a delimiter between owner and workspace name
|
||||||
|
namedWorkspace = strings.Replace(namedWorkspace, "--", "/", 1)
|
||||||
|
|
||||||
|
workspace, workspaceAgent, err := getWorkspaceAndAgent(ctx, inv, client, !disableAutostart, namedWorkspace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -509,6 +514,12 @@ func (r *RootCmd) ssh() *serpent.Command {
|
|||||||
Description: "Specifies whether to emit SSH output over stdin/stdout.",
|
Description: "Specifies whether to emit SSH output over stdin/stdout.",
|
||||||
Value: serpent.BoolOf(&stdio),
|
Value: serpent.BoolOf(&stdio),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Flag: "ssh-host-prefix",
|
||||||
|
Env: "CODER_SSH_SSH_HOST_PREFIX",
|
||||||
|
Description: "Strip this prefix from the provided hostname to determine the workspace name. This is useful when used as part of an OpenSSH proxy command.",
|
||||||
|
Value: serpent.StringOf(&hostPrefix),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Flag: "forward-agent",
|
Flag: "forward-agent",
|
||||||
FlagShorthand: "A",
|
FlagShorthand: "A",
|
||||||
|
@ -1568,6 +1568,69 @@ func TestSSH(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("SSHHostPrefix", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
client, workspace, agentToken := setupWorkspaceForAgent(t)
|
||||||
|
_, _ = tGoContext(t, func(ctx context.Context) {
|
||||||
|
// Run this async so the SSH command has to wait for
|
||||||
|
// the build and agent to connect!
|
||||||
|
_ = agenttest.New(t, client.URL, agentToken)
|
||||||
|
<-ctx.Done()
|
||||||
|
})
|
||||||
|
|
||||||
|
clientOutput, clientInput := io.Pipe()
|
||||||
|
serverOutput, serverInput := io.Pipe()
|
||||||
|
defer func() {
|
||||||
|
for _, c := range []io.Closer{clientOutput, clientInput, serverOutput, serverInput} {
|
||||||
|
_ = c.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
user, err := client.User(ctx, codersdk.Me)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
inv, root := clitest.New(t, "ssh", "--stdio", "--ssh-host-prefix", "coder.dummy.com--", fmt.Sprintf("coder.dummy.com--%s--%s", user.Username, workspace.Name))
|
||||||
|
clitest.SetupConfig(t, client, root)
|
||||||
|
inv.Stdin = clientOutput
|
||||||
|
inv.Stdout = serverInput
|
||||||
|
inv.Stderr = io.Discard
|
||||||
|
|
||||||
|
cmdDone := tGo(t, func() {
|
||||||
|
err := inv.WithContext(ctx).Run()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
conn, channels, requests, err := ssh.NewClientConn(&stdioConn{
|
||||||
|
Reader: serverOutput,
|
||||||
|
Writer: clientInput,
|
||||||
|
}, "", &ssh.ClientConfig{
|
||||||
|
// #nosec
|
||||||
|
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
sshClient := ssh.NewClient(conn, channels, requests)
|
||||||
|
session, err := sshClient.NewSession()
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer session.Close()
|
||||||
|
|
||||||
|
command := "sh -c exit"
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
command = "cmd.exe /c exit"
|
||||||
|
}
|
||||||
|
err = session.Run(command)
|
||||||
|
require.NoError(t, err)
|
||||||
|
err = sshClient.Close()
|
||||||
|
require.NoError(t, err)
|
||||||
|
_ = clientOutput.Close()
|
||||||
|
|
||||||
|
<-cmdDone
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint:paralleltest // This test uses t.Setenv, parent test MUST NOT be parallel.
|
//nolint:paralleltest // This test uses t.Setenv, parent test MUST NOT be parallel.
|
||||||
|
5
cli/testdata/coder_ssh_--help.golden
vendored
5
cli/testdata/coder_ssh_--help.golden
vendored
@ -45,6 +45,11 @@ OPTIONS:
|
|||||||
-R, --remote-forward string-array, $CODER_SSH_REMOTE_FORWARD
|
-R, --remote-forward string-array, $CODER_SSH_REMOTE_FORWARD
|
||||||
Enable remote port forwarding (remote_port:local_address:local_port).
|
Enable remote port forwarding (remote_port:local_address:local_port).
|
||||||
|
|
||||||
|
--ssh-host-prefix string, $CODER_SSH_SSH_HOST_PREFIX
|
||||||
|
Strip this prefix from the provided hostname to determine the
|
||||||
|
workspace name. This is useful when used as part of an OpenSSH proxy
|
||||||
|
command.
|
||||||
|
|
||||||
--stdio bool, $CODER_SSH_STDIO
|
--stdio bool, $CODER_SSH_STDIO
|
||||||
Specifies whether to emit SSH output over stdin/stdout.
|
Specifies whether to emit SSH output over stdin/stdout.
|
||||||
|
|
||||||
|
9
docs/reference/cli/ssh.md
generated
9
docs/reference/cli/ssh.md
generated
@ -20,6 +20,15 @@ coder ssh [flags] <workspace>
|
|||||||
|
|
||||||
Specifies whether to emit SSH output over stdin/stdout.
|
Specifies whether to emit SSH output over stdin/stdout.
|
||||||
|
|
||||||
|
### --ssh-host-prefix
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|-------------|-----------------------------------------|
|
||||||
|
| Type | <code>string</code> |
|
||||||
|
| Environment | <code>$CODER_SSH_SSH_HOST_PREFIX</code> |
|
||||||
|
|
||||||
|
Strip this prefix from the provided hostname to determine the workspace name. This is useful when used as part of an OpenSSH proxy command.
|
||||||
|
|
||||||
### -A, --forward-agent
|
### -A, --forward-agent
|
||||||
|
|
||||||
| | |
|
| | |
|
||||||
|
Reference in New Issue
Block a user