From 79535d0435c41d71b0928d32b712a00d040b6af1 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Tue, 14 Mar 2023 18:03:53 -0500 Subject: [PATCH 01/34] feat: Allow setting deployment wide ssh config settings --- cli/server.go | 9 ++++ coderd/clissh.go | 17 ++++++++ coderd/coderd.go | 10 +++++ codersdk/deployment.go | 76 ++++++++++++++++++++++++++++++++++ site/src/api/typesGenerated.ts | 13 ++++++ 5 files changed, 125 insertions(+) create mode 100644 coderd/clissh.go diff --git a/cli/server.go b/cli/server.go index 76997b2ea694a..376b71e21303b 100644 --- a/cli/server.go +++ b/cli/server.go @@ -672,6 +672,11 @@ flags, and YAML configuration. The precedence is as follows: return xerrors.Errorf("parse real ip config: %w", err) } + configSSHOptions, err := cfg.CLISSH.ParseOptions() + if err != nil { + return xerrors.Errorf("parse ssh config options \"%v\" %w", cfg.CLISSH.SSHConfigOptions, err) + } + options := &coderd.Options{ AccessURL: cfg.AccessURL.Value(), AppHostname: appHostname, @@ -696,6 +701,10 @@ flags, and YAML configuration. The precedence is as follows: LoginRateLimit: loginRateLimit, FilesRateLimit: filesRateLimit, HTTPClient: httpClient, + ConfigSSH: codersdk.CLISSHConfigResponse{ + DeploymentName: cfg.CLISSH.DeploymentName.String(), + SSHConfigOptions: configSSHOptions, + }, } if tlsConfig != nil { options.TLSCertificates = tlsConfig.Certificates diff --git a/coderd/clissh.go b/coderd/clissh.go new file mode 100644 index 0000000000000..1c7e2f20aa011 --- /dev/null +++ b/coderd/clissh.go @@ -0,0 +1,17 @@ +package coderd + +import ( + "net/http" + + "github.com/coder/coder/coderd/httpapi" +) + +// @Summary SSH information for clients +// @ID cli-ssh-config +// @Produce json +// @Tags General +// @Success 200 {object} codersdk.BuildInfoResponse +// @Router /ssh-config [get] +func (a *API) cliSSHConfig(rw http.ResponseWriter, r *http.Request) { + httpapi.Write(r.Context(), rw, http.StatusOK, a.ConfigSSH) +} diff --git a/coderd/coderd.go b/coderd/coderd.go index ed53b095751e5..3298a8f1f76f0 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -138,6 +138,9 @@ type Options struct { DeploymentValues *codersdk.DeploymentValues UpdateCheckOptions *updatecheck.Options // Set non-nil to enable update checking. + // ConfigSSH is the response clients use to configure config-ssh locally. + ConfigSSH codersdk.CLISSHConfigResponse + HTTPClient *http.Client } @@ -399,6 +402,13 @@ func New(options *Options) *API { r.Post("/csp/reports", api.logReportCSPViolations) r.Get("/buildinfo", buildInfo) + r.Route("/ssh-config", func(r chi.Router) { + // Require auth for this route to prevent leaking the SSH config. + // to non-authenticated users. Also some config settings might + // be dependent on the user. + r.Use(apiKeyMiddleware) + r.Get("/", api.cliSSHConfig) + }) r.Route("/deployment", func(r chi.Router) { r.Use(apiKeyMiddleware) r.Get("/config", api.deploymentValues) diff --git a/codersdk/deployment.go b/codersdk/deployment.go index 4135a95bfec46..72a3c3e14693e 100644 --- a/codersdk/deployment.go +++ b/codersdk/deployment.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "flag" + "fmt" "math" "net/http" "os" @@ -160,6 +161,7 @@ type DeploymentValues struct { DisablePasswordAuth clibase.Bool `json:"disable_password_auth,omitempty" typescript:",notnull"` Support SupportConfig `json:"support,omitempty" typescript:",notnull"` GitAuthProviders clibase.Struct[[]GitAuthConfig] `json:"git_auth,omitempty" typescript:",notnull"` + CLISSH CLISSHConfig `json:"cli_ssh,omitempty" typescript:",notnull"` Config clibase.String `json:"config,omitempty" typescript:",notnull"` WriteConfig clibase.Bool `json:"write_config,omitempty" typescript:",notnull"` @@ -168,6 +170,30 @@ type DeploymentValues struct { Address clibase.HostPort `json:"address,omitempty" typescript:",notnull"` } +// CLISSHConfig is configuration the cli & vscode extension use for configuring +// ssh connections. +type CLISSHConfig struct { + // DeploymentName is the config-ssh Hostname prefix + DeploymentName clibase.String + // SSHConfigOptions are additional options to add to the ssh config file. + // This will override defaults. + SSHConfigOptions clibase.Strings +} + +func (c CLISSHConfig) ParseOptions() (map[string]string, error) { + m := make(map[string]string) + for _, opt := range c.SSHConfigOptions { + // Only split once, the value could contain an equals sign. + // The key should never, so this is safe. + parts := strings.SplitN(opt, "=", 1) + if len(parts) != 2 { + return nil, fmt.Errorf("invalid config-ssh option %q", opt) + } + m[parts[0]] = parts[1] + } + return m, nil +} + type DERP struct { Server DERPServerConfig `json:"server" typescript:",notnull"` Config DERPConfig `json:"config" typescript:",notnull"` @@ -390,6 +416,11 @@ when required by your organization's security policy.`, deploymentGroupDangerous = clibase.Group{ Name: "⚠️ Dangerous", } + deploymentGroupClient = clibase.Group{ + Name: "Client", + Description: "These options change the behavior of how clients interact with the Coder. " + + "Clients include the coder cli, vs code extension, and the web UI.", + } deploymentGroupConfig = clibase.Group{ Name: "Config", Description: `Use a YAML configuration file when your server launch become unwieldy.`, @@ -1265,6 +1296,29 @@ when required by your organization's security policy.`, Group: &deploymentGroupConfig, Value: &c.Config, }, + { + Name: "CLI SSH Deployment Name", + Description: "The CLI SSH deployment name is the used in the Hostname of the ssh config.", + Flag: "cli-ssh-deployment-name", + Env: "CLI_SSH_DEPLOYMENT_NAME", + YAML: "cliSSHDeploymentName", + Group: &deploymentGroupClient, + Value: &c.CLISSH.DeploymentName, + Hidden: false, + Default: "coder", + }, + { + Name: "CLI SSH Config Options", + Description: "These cli config options will override the default ssh config options. " + + "Provide options in key=value format seperated by commas." + + "Using this incorrectly can break ssh to your deployment. Use cautiously.", + Flag: "cli-ssh-options", + Env: "CLI_SSH_OPTIONS", + YAML: "cliSSHOptions", + Group: &deploymentGroupClient, + Value: &c.CLISSH.SSHConfigOptions, + Hidden: false, + }, { Name: "Write Config", Description: ` @@ -1580,3 +1634,25 @@ type DeploymentStats struct { Workspaces WorkspaceDeploymentStats `json:"workspaces"` SessionCount SessionCountDeploymentStats `json:"session_count"` } + +type CLISSHConfigResponse struct { + DeploymentName string `json:"deployment_name"` + SSHConfigOptions map[string]string `json:"ssh_config_options"` +} + +// SSHConfiguration returns information about the SSH configuration for the +// Coder instance. +func (c *Client) SSHConfiguration(ctx context.Context) (CLISSHConfigResponse, error) { + res, err := c.Request(ctx, http.MethodGet, "/api/v2/ssh-config", nil) + if err != nil { + return CLISSHConfigResponse{}, err + } + defer res.Body.Close() + + if res.StatusCode != http.StatusOK { + return CLISSHConfigResponse{}, ReadBodyAsError(res) + } + + var cliConfig CLISSHConfigResponse + return cliConfig, json.NewDecoder(res.Body).Decode(&cliConfig) +} diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 9cb75fd64fa6d..e6cc03de08284 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -135,6 +135,18 @@ export interface BuildInfoResponse { readonly version: string } +// From codersdk/deployment.go +export interface CLISSHConfig { + readonly DeploymentName: string + readonly SSHConfigOptions: string[] +} + +// From codersdk/deployment.go +export interface CLISSHConfigResponse { + readonly deployment_name: string + readonly ssh_config_options: Record +} + // From codersdk/parameters.go export interface ComputedParameter extends Parameter { readonly source_value: string @@ -359,6 +371,7 @@ export interface DeploymentValues { // Named type "github.com/coder/coder/cli/clibase.Struct[[]github.com/coder/coder/codersdk.GitAuthConfig]" unknown, using "any" // eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO explain why this is needed readonly git_auth?: any + readonly cli_ssh?: CLISSHConfig readonly config?: string readonly write_config?: boolean // Named type "github.com/coder/coder/cli/clibase.HostPort" unknown, using "any" From f0eb12330e74aa0375277fbb5a8983c57dc62667 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 15 Mar 2023 10:22:52 -0500 Subject: [PATCH 02/34] feat: config-ssh respects deployment ssh config Also properly overwrites --- cli/configssh.go | 121 +++++++++++++++++++++++++++++------- cli/server.go | 2 +- coderd/coderd.go | 3 + codersdk/deployment.go | 22 +++++-- codersdk/deployment_test.go | 82 ++++++++++++++++++++++++ 5 files changed, 202 insertions(+), 28 deletions(-) diff --git a/cli/configssh.go b/cli/configssh.go index 090489c2ba611..159a6d629eefa 100644 --- a/cli/configssh.go +++ b/cli/configssh.go @@ -8,6 +8,7 @@ import ( "fmt" "io" "io/fs" + "net/http" "os" "path/filepath" "runtime" @@ -48,6 +49,38 @@ type sshConfigOptions struct { sshOptions []string } +// add expects an option in the form of "option=value" or "option value". +// It will override any existing option with the same key to prevent duplicates. +// Invalid options will return an error. +func (o *sshConfigOptions) addOptions(options ...string) error { + for _, option := range options { + err := o.addOption(option) + if err != nil { + return err + } + } + return nil +} + +func (o *sshConfigOptions) addOption(option string) error { + key, _, err := codersdk.ParseSSHConfigOption(option) + if err != nil { + return err + } + for i, existing := range o.sshOptions { + // Override existing option. + if len(existing) < len(key) { + continue + } + if strings.EqualFold(existing[:len(key)], key) { + o.sshOptions[i] = option + return nil + } + } + o.sshOptions = append(o.sshOptions, option) + return nil +} + func (o sshConfigOptions) equal(other sshConfigOptions) bool { // Compare without side-effects or regard to order. opt1 := slices.Clone(o.sshOptions) @@ -156,12 +189,13 @@ func configSSH() *cobra.Command { ), Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, _ []string) error { + ctx := cmd.Context() client, err := CreateClient(cmd) if err != nil { return err } - recvWorkspaceConfigs := sshPrepareWorkspaceConfigs(cmd.Context(), client) + recvWorkspaceConfigs := sshPrepareWorkspaceConfigs(ctx, client) out := cmd.OutOrStdout() if dryRun { @@ -269,6 +303,26 @@ func configSSH() *cobra.Command { if err != nil { return xerrors.Errorf("fetch workspace configs failed: %w", err) } + + coderdConfig, err := client.SSHConfiguration(ctx) + if err != nil { + // If the error is 404, this deployment does not support + // this endpoint yet. + // TODO: Remove this in 2 months (May 2023). Just return the error + // and remove this 404 check. + var sdkErr *codersdk.Error + if xerrors.As(err, &sdkErr) { + // If it is 404, continue. + if sdkErr.StatusCode() == http.StatusNotFound { + coderdConfig.DeploymentName = "coder" + } else { + return xerrors.Errorf("fetch coderd config failed: %w", err) + } + } else { + return xerrors.Errorf("fetch coderd config failed: %w", err) + } + } + // Ensure stable sorting of output. slices.SortFunc(workspaceConfigs, func(a, b sshWorkspaceConfig) bool { return a.Name < b.Name @@ -277,34 +331,59 @@ func configSSH() *cobra.Command { sort.Strings(wc.Hosts) // Write agent configuration. for _, hostname := range wc.Hosts { - configOptions := []string{ - "Host coder." + hostname, - } - for _, option := range sshConfigOpts.sshOptions { - configOptions = append(configOptions, "\t"+option) - } - configOptions = append(configOptions, - "\tHostName coder."+hostname, - "\tConnectTimeout=0", - "\tStrictHostKeyChecking=no", + sshHostname := fmt.Sprintf("%s.%s", coderdConfig.DeploymentName, hostname) + var configOptions sshConfigOptions + // Add standard options. + err := configOptions.addOptions( + "HostName "+sshHostname, + "ConnectTimeout=0", + "StrictHostKeyChecking=no", // Without this, the "REMOTE HOST IDENTITY CHANGED" // message will appear. - "\tUserKnownHostsFile=/dev/null", + "UserKnownHostsFile=/dev/null", // This disables the "Warning: Permanently added 'hostname' (RSA) to the list of known hosts." // message from appearing on every SSH. This happens because we ignore the known hosts. - "\tLogLevel ERROR", + "LogLevel ERROR", ) + if err != nil { + return err + } + if !skipProxyCommand { - configOptions = append( - configOptions, - fmt.Sprintf( - "\tProxyCommand %s --global-config %s ssh --stdio %s", - escapedCoderBinary, escapedGlobalConfig, hostname, - ), - ) + err := configOptions.addOptions(fmt.Sprintf( + "ProxyCommand %s --global-config %s ssh --stdio %s", + escapedCoderBinary, escapedGlobalConfig, hostname, + )) + if err != nil { + return err + } + } + + // Override with deployment options + for k, v := range coderdConfig.SSHConfigOptions { + opt := fmt.Sprintf("%s %s", k, v) + err := configOptions.addOptions(opt) + if err != nil { + return xerrors.Errorf("add coderd config option %q: %w", opt, err) + } + } + // Override with flag options + for _, opt := range sshConfigOpts.sshOptions { + err := configOptions.addOptions(opt) + if err != nil { + return xerrors.Errorf("add flag config option %q: %w", opt, err) + } + } + + hostBlock := []string{ + "Host " + sshHostname, + } + // Prefix with '\t' + for _, v := range configOptions.sshOptions { + hostBlock = append(hostBlock, "\t"+v) } - _, _ = buf.WriteString(strings.Join(configOptions, "\n")) + _, _ = buf.WriteString(strings.Join(hostBlock, "\n")) _ = buf.WriteByte('\n') } } diff --git a/cli/server.go b/cli/server.go index 376b71e21303b..e5dd662037e50 100644 --- a/cli/server.go +++ b/cli/server.go @@ -674,7 +674,7 @@ flags, and YAML configuration. The precedence is as follows: configSSHOptions, err := cfg.CLISSH.ParseOptions() if err != nil { - return xerrors.Errorf("parse ssh config options \"%v\" %w", cfg.CLISSH.SSHConfigOptions, err) + return xerrors.Errorf("parse ssh config options %q: %w", cfg.CLISSH.SSHConfigOptions.String(), err) } options := &coderd.Options{ diff --git a/coderd/coderd.go b/coderd/coderd.go index 3298a8f1f76f0..e6fb6c09c223e 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -213,6 +213,9 @@ func New(options *Options) *API { if options.Auditor == nil { options.Auditor = audit.NewNop() } + if options.ConfigSSH.DeploymentName == "" { + options.ConfigSSH.DeploymentName = "coder" + } // TODO: remove this once we promote authz_querier out of experiments. if experiments.Enabled(codersdk.ExperimentAuthzQuerier) { options.Database = dbauthz.New( diff --git a/codersdk/deployment.go b/codersdk/deployment.go index 72a3c3e14693e..82dab39be6832 100644 --- a/codersdk/deployment.go +++ b/codersdk/deployment.go @@ -183,17 +183,27 @@ type CLISSHConfig struct { func (c CLISSHConfig) ParseOptions() (map[string]string, error) { m := make(map[string]string) for _, opt := range c.SSHConfigOptions { - // Only split once, the value could contain an equals sign. - // The key should never, so this is safe. - parts := strings.SplitN(opt, "=", 1) - if len(parts) != 2 { - return nil, fmt.Errorf("invalid config-ssh option %q", opt) + key, value, err := ParseSSHConfigOption(opt) + if err != nil { + return nil, err } - m[parts[0]] = parts[1] + m[key] = value } return m, nil } +// ParseSSHConfigOption parses a single ssh config option into it's key/value pair. +func ParseSSHConfigOption(opt string) (key string, value string, err error) { + // An equal sign or whitespace is the separator between the key and value. + idx := strings.IndexFunc(opt, func(r rune) bool { + return r == ' ' || r == '=' + }) + if idx == -1 { + return "", "", fmt.Errorf("invalid config-ssh option %q", opt) + } + return opt[:idx], opt[idx+1:], nil +} + type DERP struct { Server DERPServerConfig `json:"server" typescript:",notnull"` Config DERPConfig `json:"config" typescript:",notnull"` diff --git a/codersdk/deployment_test.go b/codersdk/deployment_test.go index 54a1af10ff256..59060b6d9efe2 100644 --- a/codersdk/deployment_test.go +++ b/codersdk/deployment_test.go @@ -3,6 +3,9 @@ package codersdk_test import ( "testing" + "github.com/coder/coder/cli/clibase" + "github.com/stretchr/testify/require" + "github.com/coder/coder/codersdk" ) @@ -105,3 +108,82 @@ func TestDeploymentValues_HighlyConfigurable(t *testing.T) { t.Errorf("Excluded option %q is not in the deployment config. Remove it?", opt) } } + +func TestCLISSHConfig_ParseOptions(t *testing.T) { + t.Parallel() + + testCases := []struct { + Name string + ConfigOptions clibase.Strings + ExpectError bool + Expect map[string]string + }{ + { + Name: "Empty", + ConfigOptions: []string{}, + Expect: map[string]string{}, + }, + { + Name: "Whitespace", + ConfigOptions: []string{ + "test value", + }, + Expect: map[string]string{ + "test": "value", + }, + }, + { + Name: "SimpleValueEqual", + ConfigOptions: []string{ + "test=value", + }, + Expect: map[string]string{ + "test": "value", + }, + }, + { + Name: "SimpleValues", + ConfigOptions: []string{ + "test=value", + "foo=bar", + }, + Expect: map[string]string{ + "test": "value", + "foo": "bar", + }, + }, + { + Name: "ValueWithQuote", + ConfigOptions: []string{ + "bar=buzz=bazz", + }, + Expect: map[string]string{ + "bar": "buzz=bazz", + }, + }, + { + Name: "NoEquals", + ConfigOptions: []string{ + "foobar", + }, + ExpectError: true, + }, + } + + for _, tt := range testCases { + tt := tt + t.Run(tt.Name, func(t *testing.T) { + t.Parallel() + c := codersdk.CLISSHConfig{ + SSHConfigOptions: tt.ConfigOptions, + } + got, err := c.ParseOptions() + if tt.ExpectError { + require.Error(t, err, tt.ConfigOptions.String()) + } else { + require.NoError(t, err, tt.ConfigOptions.String()) + require.Equalf(t, tt.Expect, got, tt.ConfigOptions.String()) + } + }) + } +} From 4beeb62384c28e3bf072c437c4e9c277e7df1dcd Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 15 Mar 2023 10:32:19 -0500 Subject: [PATCH 03/34] Catch early parse error --- cli/configssh.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cli/configssh.go b/cli/configssh.go index 159a6d629eefa..ae1cf4e9e48a5 100644 --- a/cli/configssh.go +++ b/cli/configssh.go @@ -254,6 +254,13 @@ func configSSH() *cobra.Command { if usePreviousOpts && lastConfig != nil { sshConfigOpts = *lastConfig } else if lastConfig != nil && !sshConfigOpts.equal(*lastConfig) { + for _, v := range sshConfigOpts.sshOptions { + // If the user passes an invalid option, we should catch + // this early. + if _, _, err := codersdk.ParseSSHConfigOption(v); err != nil { + return xerrors.Errorf("invalid option from flag: %w", err) + } + } newOpts := sshConfigOpts.asList() newOptsMsg := "\n\n New options: none" if len(newOpts) > 0 { From 08f5d3ddd7c31c11d227868fd8d23c8b3aaeb8db Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 15 Mar 2023 10:45:58 -0500 Subject: [PATCH 04/34] Add to unit test --- cli/configssh_test.go | 20 ++++++++++++++++++-- coderd/coderdtest/coderdtest.go | 3 +++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/cli/configssh_test.go b/cli/configssh_test.go index 343a6af43dc58..ca56bd7ff8e97 100644 --- a/cli/configssh_test.go +++ b/cli/configssh_test.go @@ -24,6 +24,7 @@ import ( "github.com/coder/coder/agent" "github.com/coder/coder/cli/clitest" "github.com/coder/coder/coderd/coderdtest" + "github.com/coder/coder/codersdk" "github.com/coder/coder/codersdk/agentsdk" "github.com/coder/coder/provisioner/echo" "github.com/coder/coder/provisionersdk/proto" @@ -63,7 +64,18 @@ func sshConfigFileRead(t *testing.T, name string) string { func TestConfigSSH(t *testing.T) { t.Parallel() - client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) + const hostname = "test-coder" + const expectedKey = "ConnectionAttempts" + client := coderdtest.New(t, &coderdtest.Options{ + IncludeProvisionerDaemon: true, + ConfigSSH: codersdk.CLISSHConfigResponse{ + DeploymentName: "test-coder", + SSHConfigOptions: map[string]string{ + // Something we can test for + expectedKey: "3", + }, + }, + }) user := coderdtest.CreateFirstUser(t, client) authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ @@ -181,9 +193,13 @@ func TestConfigSSH(t *testing.T) { <-doneChan + fileContents, err := os.ReadFile(sshConfigFile) + require.NoError(t, err, "read ssh config file") + require.Contains(t, string(fileContents), expectedKey, "ssh config file contains expected key") + home := filepath.Dir(filepath.Dir(sshConfigFile)) // #nosec - sshCmd := exec.Command("ssh", "-F", sshConfigFile, "coder."+workspace.Name, "echo", "test") + sshCmd := exec.Command("ssh", "-F", sshConfigFile, hostname+"."+workspace.Name, "echo", "test") pty = ptytest.New(t) // Set HOME because coder config is included from ~/.ssh/coder. sshCmd.Env = append(sshCmd.Env, fmt.Sprintf("HOME=%s", home)) diff --git a/coderd/coderdtest/coderdtest.go b/coderd/coderdtest/coderdtest.go index 987f912c35165..a04398dd72237 100644 --- a/coderd/coderdtest/coderdtest.go +++ b/coderd/coderdtest/coderdtest.go @@ -126,6 +126,8 @@ type Options struct { Database database.Store Pubsub database.Pubsub + ConfigSSH codersdk.CLISSHConfigResponse + SwaggerEndpoint bool } @@ -333,6 +335,7 @@ func NewOptions(t *testing.T, options *Options) (func(http.Handler), context.Can UpdateCheckOptions: options.UpdateCheckOptions, SwaggerEndpoint: options.SwaggerEndpoint, AppSigningKey: AppSigningKey, + ConfigSSH: options.ConfigSSH, } } From c8c51897425d9c0831f1f93d691fdd3232ec10a2 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 15 Mar 2023 10:46:30 -0500 Subject: [PATCH 05/34] fix typo --- codersdk/deployment.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codersdk/deployment.go b/codersdk/deployment.go index 82dab39be6832..0af5d237decc7 100644 --- a/codersdk/deployment.go +++ b/codersdk/deployment.go @@ -1320,7 +1320,7 @@ when required by your organization's security policy.`, { Name: "CLI SSH Config Options", Description: "These cli config options will override the default ssh config options. " + - "Provide options in key=value format seperated by commas." + + "Provide options in key=value format separated by commas." + "Using this incorrectly can break ssh to your deployment. Use cautiously.", Flag: "cli-ssh-options", Env: "CLI_SSH_OPTIONS", From 96ad4bc83fc37f49b2a147a475707f83b60816aa Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 15 Mar 2023 10:58:54 -0500 Subject: [PATCH 06/34] Add unit test --- cli/configssh.go | 12 ++++-- cli/configssh_internal_test.go | 78 ++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 3 deletions(-) diff --git a/cli/configssh.go b/cli/configssh.go index ae1cf4e9e48a5..be10d82d634e3 100644 --- a/cli/configssh.go +++ b/cli/configssh.go @@ -68,11 +68,17 @@ func (o *sshConfigOptions) addOption(option string) error { return err } for i, existing := range o.sshOptions { - // Override existing option. - if len(existing) < len(key) { + // Override existing option if they share the same key. + // This is case-insensitive. Parsing each time might be a little slow, + // but it is ok. + // + existingKey, _, err := codersdk.ParseSSHConfigOption(existing) + if err != nil { + // Don't mess with original values if there is an error. + // This could have come from the user's manual edits. continue } - if strings.EqualFold(existing[:len(key)], key) { + if strings.EqualFold(existingKey, key) { o.sshOptions[i] = option return nil } diff --git a/cli/configssh_internal_test.go b/cli/configssh_internal_test.go index 88de43b73a104..201dc9fea5c96 100644 --- a/cli/configssh_internal_test.go +++ b/cli/configssh_internal_test.go @@ -5,6 +5,7 @@ import ( "os/exec" "path/filepath" "runtime" + "sort" "strings" "testing" @@ -179,3 +180,80 @@ func Test_sshConfigExecEscape(t *testing.T) { }) } } + +func Test_sshConfigOptions_addOption(t *testing.T) { + t.Parallel() + testCases := []struct { + Name string + Start []string + Add []string + Expect []string + ExpectError bool + }{ + { + Name: "Empty", + }, + { + Name: "AddOne", + Add: []string{"foo bar"}, + Expect: []string{ + "foo bar", + }, + }, + { + Name: "Replace", + Start: []string{ + "foo bar", + }, + Add: []string{"Foo baz"}, + Expect: []string{ + "Foo baz", + }, + }, + { + Name: "AddAndReplace", + Start: []string{ + "a b", + "foo bar", + "buzz bazz", + }, + Add: []string{ + "b c", + "A hello", + "hello world", + }, + Expect: []string{ + "foo bar", + "buzz bazz", + "b c", + "A hello", + "hello world", + }, + }, + { + Name: "Error", + Add: []string{"novalue"}, + ExpectError: true, + }, + } + + for _, tt := range testCases { + tt := tt + t.Run(tt.Name, func(t *testing.T) { + t.Parallel() + + o := sshConfigOptions{ + sshOptions: tt.Start, + } + err := o.addOptions(tt.Add...) + if tt.ExpectError { + require.Error(t, err) + return + } + require.NoError(t, err) + sort.Strings(tt.Expect) + sort.Strings(o.sshOptions) + require.Equal(t, tt.Expect, o.sshOptions) + }) + } +} From f9f4a8fa0f4c2dab054ecb94f4fa1a7c663976e0 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 15 Mar 2023 11:15:21 -0500 Subject: [PATCH 07/34] Fix output --- cli/configssh.go | 2 +- coderd/clissh.go | 2 +- coderd/coderd.go | 2 +- codersdk/deployment.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cli/configssh.go b/cli/configssh.go index be10d82d634e3..a7857ebf0846e 100644 --- a/cli/configssh.go +++ b/cli/configssh.go @@ -455,7 +455,7 @@ func configSSH() *cobra.Command { if len(workspaceConfigs) > 0 { _, _ = fmt.Fprintln(out, "You should now be able to ssh into your workspace.") - _, _ = fmt.Fprintf(out, "For example, try running:\n\n\t$ ssh coder.%s\n", workspaceConfigs[0].Name) + _, _ = fmt.Fprintf(out, "For example, try running:\n\n\t$ ssh %s.%s\n", coderdConfig.DeploymentName, workspaceConfigs[0].Name) } else { _, _ = fmt.Fprint(out, "You don't have any workspaces yet, try creating one with:\n\n\t$ coder create \n") } diff --git a/coderd/clissh.go b/coderd/clissh.go index 1c7e2f20aa011..7adf1554370c2 100644 --- a/coderd/clissh.go +++ b/coderd/clissh.go @@ -11,7 +11,7 @@ import ( // @Produce json // @Tags General // @Success 200 {object} codersdk.BuildInfoResponse -// @Router /ssh-config [get] +// @Router /config-ssh [get] func (a *API) cliSSHConfig(rw http.ResponseWriter, r *http.Request) { httpapi.Write(r.Context(), rw, http.StatusOK, a.ConfigSSH) } diff --git a/coderd/coderd.go b/coderd/coderd.go index e6fb6c09c223e..a0378f5954203 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -405,7 +405,7 @@ func New(options *Options) *API { r.Post("/csp/reports", api.logReportCSPViolations) r.Get("/buildinfo", buildInfo) - r.Route("/ssh-config", func(r chi.Router) { + r.Route("/config-ssh", func(r chi.Router) { // Require auth for this route to prevent leaking the SSH config. // to non-authenticated users. Also some config settings might // be dependent on the user. diff --git a/codersdk/deployment.go b/codersdk/deployment.go index 0af5d237decc7..70ae71ea5107f 100644 --- a/codersdk/deployment.go +++ b/codersdk/deployment.go @@ -1653,7 +1653,7 @@ type CLISSHConfigResponse struct { // SSHConfiguration returns information about the SSH configuration for the // Coder instance. func (c *Client) SSHConfiguration(ctx context.Context) (CLISSHConfigResponse, error) { - res, err := c.Request(ctx, http.MethodGet, "/api/v2/ssh-config", nil) + res, err := c.Request(ctx, http.MethodGet, "/api/v2/config-ssh", nil) if err != nil { return CLISSHConfigResponse{}, err } From ebf9eb9934207326cc3fe6f7d595b14b0c47834a Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 15 Mar 2023 11:16:50 -0500 Subject: [PATCH 08/34] Make gen --- coderd/apidoc/docs.go | 39 ++++++++++++++++++++++++++++++++++++++ coderd/apidoc/swagger.json | 35 ++++++++++++++++++++++++++++++++++ docs/api/general.md | 33 ++++++++++++++++++++++++++++++++ docs/api/schemas.md | 25 ++++++++++++++++++++++++ 4 files changed, 132 insertions(+) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 5785cb57f4ac8..e8120bb007f15 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -304,6 +304,26 @@ const docTemplate = `{ } } }, + "/config-ssh": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "General" + ], + "summary": "SSH information for clients", + "operationId": "cli-ssh-config", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.BuildInfoResponse" + } + } + } + } + }, "/csp/reports": { "post": { "security": [ @@ -5938,6 +5958,22 @@ const docTemplate = `{ "BuildReasonAutostop" ] }, + "codersdk.CLISSHConfig": { + "type": "object", + "properties": { + "deploymentName": { + "description": "DeploymentName is the config-ssh Hostname prefix", + "type": "string" + }, + "sshconfigOptions": { + "description": "SSHConfigOptions are additional options to add to the ssh config file.\nThis will override defaults.", + "type": "array", + "items": { + "type": "string" + } + } + } + }, "codersdk.CreateFirstUserRequest": { "type": "object", "required": [ @@ -6537,6 +6573,9 @@ const docTemplate = `{ "cache_directory": { "type": "string" }, + "cli_ssh": { + "$ref": "#/definitions/codersdk.CLISSHConfig" + }, "config": { "type": "string" }, diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index dc7a9dd435e4a..897b3c5ec2de4 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -258,6 +258,22 @@ } } }, + "/config-ssh": { + "get": { + "produces": ["application/json"], + "tags": ["General"], + "summary": "SSH information for clients", + "operationId": "cli-ssh-config", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.BuildInfoResponse" + } + } + } + } + }, "/csp/reports": { "post": { "security": [ @@ -5290,6 +5306,22 @@ "BuildReasonAutostop" ] }, + "codersdk.CLISSHConfig": { + "type": "object", + "properties": { + "deploymentName": { + "description": "DeploymentName is the config-ssh Hostname prefix", + "type": "string" + }, + "sshconfigOptions": { + "description": "SSHConfigOptions are additional options to add to the ssh config file.\nThis will override defaults.", + "type": "array", + "items": { + "type": "string" + } + } + } + }, "codersdk.CreateFirstUserRequest": { "type": "object", "required": ["email", "password", "username"], @@ -5837,6 +5869,9 @@ "cache_directory": { "type": "string" }, + "cli_ssh": { + "$ref": "#/definitions/codersdk.CLISSHConfig" + }, "config": { "type": "string" }, diff --git a/docs/api/general.md b/docs/api/general.md index 679b6405af156..1e4280180d9b3 100644 --- a/docs/api/general.md +++ b/docs/api/general.md @@ -64,6 +64,35 @@ curl -X GET http://coder-server:8080/api/v2/buildinfo \ | ------ | ------------------------------------------------------- | ----------- | ------------------------------------------------------------------ | | 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.BuildInfoResponse](schemas.md#codersdkbuildinforesponse) | +## SSH information for clients + +### Code samples + +```shell +# Example request using curl +curl -X GET http://coder-server:8080/api/v2/config-ssh \ + -H 'Accept: application/json' +``` + +`GET /config-ssh` + +### Example responses + +> 200 Response + +```json +{ + "external_url": "string", + "version": "string" +} +``` + +### Responses + +| Status | Meaning | Description | Schema | +| ------ | ------------------------------------------------------- | ----------- | ------------------------------------------------------------------ | +| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.BuildInfoResponse](schemas.md#codersdkbuildinforesponse) | + ## Report CSP violations ### Code samples @@ -154,6 +183,10 @@ curl -X GET http://coder-server:8080/api/v2/deployment/config \ "autobuild_poll_interval": 0, "browser_only": true, "cache_directory": "string", + "cli_ssh": { + "deploymentName": "string", + "sshconfigOptions": ["string"] + }, "config": "string", "dangerous": { "allow_path_app_sharing": true, diff --git a/docs/api/schemas.md b/docs/api/schemas.md index 7ee906d6195b7..a09501bb369d2 100644 --- a/docs/api/schemas.md +++ b/docs/api/schemas.md @@ -1100,6 +1100,22 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in | `autostart` | | `autostop` | +## codersdk.CLISSHConfig + +```json +{ + "deploymentName": "string", + "sshconfigOptions": ["string"] +} +``` + +### Properties + +| Name | Type | Required | Restrictions | Description | +| ------------------ | --------------- | -------- | ------------ | --------------------------------------------------------------------------------------------------- | +| `deploymentName` | string | false | | Deploymentname is the config-ssh Hostname prefix | +| `sshconfigOptions` | array of string | false | | Sshconfigoptions are additional options to add to the ssh config file. This will override defaults. | + ## codersdk.CreateFirstUserRequest ```json @@ -1686,6 +1702,10 @@ CreateParameterRequest is a structure used to create a new parameter value for a "autobuild_poll_interval": 0, "browser_only": true, "cache_directory": "string", + "cli_ssh": { + "deploymentName": "string", + "sshconfigOptions": ["string"] + }, "config": "string", "dangerous": { "allow_path_app_sharing": true, @@ -2026,6 +2046,10 @@ CreateParameterRequest is a structure used to create a new parameter value for a "autobuild_poll_interval": 0, "browser_only": true, "cache_directory": "string", + "cli_ssh": { + "deploymentName": "string", + "sshconfigOptions": ["string"] + }, "config": "string", "dangerous": { "allow_path_app_sharing": true, @@ -2237,6 +2261,7 @@ CreateParameterRequest is a structure used to create a new parameter value for a | `autobuild_poll_interval` | integer | false | | | | `browser_only` | boolean | false | | | | `cache_directory` | string | false | | | +| `cli_ssh` | [codersdk.CLISSHConfig](#codersdkclisshconfig) | false | | | | `config` | string | false | | | | `dangerous` | [codersdk.DangerousConfig](#codersdkdangerousconfig) | false | | | | `derp` | [codersdk.DERP](#codersdkderp) | false | | | From 119695bf8fe9eaafe7e6f59bd902f37e6eaf46bd Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 15 Mar 2023 11:20:18 -0500 Subject: [PATCH 09/34] Simplify if/else --- cli/configssh.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/cli/configssh.go b/cli/configssh.go index a7857ebf0846e..279fde82fdd17 100644 --- a/cli/configssh.go +++ b/cli/configssh.go @@ -320,20 +320,20 @@ func configSSH() *cobra.Command { coderdConfig, err := client.SSHConfiguration(ctx) if err != nil { // If the error is 404, this deployment does not support - // this endpoint yet. + // this endpoint yet. Do not error, just assume defaults. // TODO: Remove this in 2 months (May 2023). Just return the error // and remove this 404 check. var sdkErr *codersdk.Error - if xerrors.As(err, &sdkErr) { - // If it is 404, continue. - if sdkErr.StatusCode() == http.StatusNotFound { - coderdConfig.DeploymentName = "coder" - } else { - return xerrors.Errorf("fetch coderd config failed: %w", err) - } - } else { + if !xerrors.As(err, &sdkErr) { + // not an SDK error, return the original error. + return xerrors.Errorf("fetch coderd config failed: %w", err) + } + + if sdkErr.StatusCode() != http.StatusNotFound { + // Not a 404, return the original error. return xerrors.Errorf("fetch coderd config failed: %w", err) } + coderdConfig.DeploymentName = "coder" } // Ensure stable sorting of output. From b8f324245e83736b327d97dea34c78a3707f7ee6 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 15 Mar 2023 11:26:52 -0500 Subject: [PATCH 10/34] Fix AutorizeAllEndpoints --- coderd/coderdtest/authorize.go | 1 + 1 file changed, 1 insertion(+) diff --git a/coderd/coderdtest/authorize.go b/coderd/coderdtest/authorize.go index 4758b1ee46923..b83dcfa963f74 100644 --- a/coderd/coderdtest/authorize.go +++ b/coderd/coderdtest/authorize.go @@ -57,6 +57,7 @@ func AGPLRoutes(a *AuthTester) (map[string]string, map[string]RouteCheck) { "POST:/api/v2/csp/reports": {NoAuthorize: true}, "POST:/api/v2/authcheck": {NoAuthorize: true}, "GET:/api/v2/applications/host": {NoAuthorize: true}, + "GET:/api/v2/config-ssh": {NoAuthorize: true, StatusCode: http.StatusOK}, // Has it's own auth "GET:/api/v2/users/oauth2/github/callback": {NoAuthorize: true}, From b082a5ac456e756f038f0c9df4bdd4b454739722 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 15 Mar 2023 11:47:58 -0500 Subject: [PATCH 11/34] Fic swager docs --- coderd/clissh.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/coderd/clissh.go b/coderd/clissh.go index 7adf1554370c2..b75eec0c738eb 100644 --- a/coderd/clissh.go +++ b/coderd/clissh.go @@ -6,11 +6,12 @@ import ( "github.com/coder/coder/coderd/httpapi" ) -// @Summary SSH information for clients +// @Summary CLI SSH Config // @ID cli-ssh-config +// @Security CoderSessionToken // @Produce json // @Tags General -// @Success 200 {object} codersdk.BuildInfoResponse +// @Success 200 {object} codersdk.CLISSHConfigResponse // @Router /config-ssh [get] func (a *API) cliSSHConfig(rw http.ResponseWriter, r *http.Request) { httpapi.Write(r.Context(), rw, http.StatusOK, a.ConfigSSH) From 4a1e3c2cd3c01a5b670286ccc7ea0a63f2e167a5 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 15 Mar 2023 13:01:21 -0500 Subject: [PATCH 12/34] Make gen --- coderd/apidoc/docs.go | 23 +++++++++++++++++++++-- coderd/apidoc/swagger.json | 23 +++++++++++++++++++++-- docs/api/general.md | 20 +++++++++++++------- docs/api/schemas.md | 20 ++++++++++++++++++++ 4 files changed, 75 insertions(+), 11 deletions(-) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index e8120bb007f15..bb9d899cdb263 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -306,19 +306,24 @@ const docTemplate = `{ }, "/config-ssh": { "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], "produces": [ "application/json" ], "tags": [ "General" ], - "summary": "SSH information for clients", + "summary": "CLI SSH Config", "operationId": "cli-ssh-config", "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/codersdk.BuildInfoResponse" + "$ref": "#/definitions/codersdk.CLISSHConfigResponse" } } } @@ -5974,6 +5979,20 @@ const docTemplate = `{ } } }, + "codersdk.CLISSHConfigResponse": { + "type": "object", + "properties": { + "deployment_name": { + "type": "string" + }, + "ssh_config_options": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, "codersdk.CreateFirstUserRequest": { "type": "object", "required": [ diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 897b3c5ec2de4..6301786b68fa2 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -260,15 +260,20 @@ }, "/config-ssh": { "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], "produces": ["application/json"], "tags": ["General"], - "summary": "SSH information for clients", + "summary": "CLI SSH Config", "operationId": "cli-ssh-config", "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/codersdk.BuildInfoResponse" + "$ref": "#/definitions/codersdk.CLISSHConfigResponse" } } } @@ -5322,6 +5327,20 @@ } } }, + "codersdk.CLISSHConfigResponse": { + "type": "object", + "properties": { + "deployment_name": { + "type": "string" + }, + "ssh_config_options": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, "codersdk.CreateFirstUserRequest": { "type": "object", "required": ["email", "password", "username"], diff --git a/docs/api/general.md b/docs/api/general.md index 1e4280180d9b3..7e5eb351e1c3a 100644 --- a/docs/api/general.md +++ b/docs/api/general.md @@ -64,14 +64,15 @@ curl -X GET http://coder-server:8080/api/v2/buildinfo \ | ------ | ------------------------------------------------------- | ----------- | ------------------------------------------------------------------ | | 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.BuildInfoResponse](schemas.md#codersdkbuildinforesponse) | -## SSH information for clients +## CLI SSH Config ### Code samples ```shell # Example request using curl curl -X GET http://coder-server:8080/api/v2/config-ssh \ - -H 'Accept: application/json' + -H 'Accept: application/json' \ + -H 'Coder-Session-Token: API_KEY' ``` `GET /config-ssh` @@ -82,16 +83,21 @@ curl -X GET http://coder-server:8080/api/v2/config-ssh \ ```json { - "external_url": "string", - "version": "string" + "deployment_name": "string", + "ssh_config_options": { + "property1": "string", + "property2": "string" + } } ``` ### Responses -| Status | Meaning | Description | Schema | -| ------ | ------------------------------------------------------- | ----------- | ------------------------------------------------------------------ | -| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.BuildInfoResponse](schemas.md#codersdkbuildinforesponse) | +| Status | Meaning | Description | Schema | +| ------ | ------------------------------------------------------- | ----------- | ------------------------------------------------------------------------ | +| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.CLISSHConfigResponse](schemas.md#codersdkclisshconfigresponse) | + +To perform this operation, you must be authenticated. [Learn more](authentication.md). ## Report CSP violations diff --git a/docs/api/schemas.md b/docs/api/schemas.md index a09501bb369d2..9fefe09b64dc6 100644 --- a/docs/api/schemas.md +++ b/docs/api/schemas.md @@ -1116,6 +1116,26 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in | `deploymentName` | string | false | | Deploymentname is the config-ssh Hostname prefix | | `sshconfigOptions` | array of string | false | | Sshconfigoptions are additional options to add to the ssh config file. This will override defaults. | +## codersdk.CLISSHConfigResponse + +```json +{ + "deployment_name": "string", + "ssh_config_options": { + "property1": "string", + "property2": "string" + } +} +``` + +### Properties + +| Name | Type | Required | Restrictions | Description | +| -------------------- | ------ | -------- | ------------ | ----------- | +| `deployment_name` | string | false | | | +| `ssh_config_options` | object | false | | | +| » `[any property]` | string | false | | | + ## codersdk.CreateFirstUserRequest ```json From 01ea08f0fed5c7270b5ba129e3fc520ad62982eb Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 15 Mar 2023 15:04:17 -0500 Subject: [PATCH 13/34] The '.' is now configurable --- cli/configssh.go | 6 +++--- cli/configssh_test.go | 2 +- cli/server.go | 2 +- coderd/coderd.go | 4 ++-- codersdk/deployment.go | 12 ++++++------ 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/cli/configssh.go b/cli/configssh.go index 279fde82fdd17..d527eb6bf4cc7 100644 --- a/cli/configssh.go +++ b/cli/configssh.go @@ -333,7 +333,7 @@ func configSSH() *cobra.Command { // Not a 404, return the original error. return xerrors.Errorf("fetch coderd config failed: %w", err) } - coderdConfig.DeploymentName = "coder" + coderdConfig.HostnamePrefix = "coder." } // Ensure stable sorting of output. @@ -344,7 +344,7 @@ func configSSH() *cobra.Command { sort.Strings(wc.Hosts) // Write agent configuration. for _, hostname := range wc.Hosts { - sshHostname := fmt.Sprintf("%s.%s", coderdConfig.DeploymentName, hostname) + sshHostname := fmt.Sprintf("%s%s", coderdConfig.HostnamePrefix, hostname) var configOptions sshConfigOptions // Add standard options. err := configOptions.addOptions( @@ -455,7 +455,7 @@ func configSSH() *cobra.Command { if len(workspaceConfigs) > 0 { _, _ = fmt.Fprintln(out, "You should now be able to ssh into your workspace.") - _, _ = fmt.Fprintf(out, "For example, try running:\n\n\t$ ssh %s.%s\n", coderdConfig.DeploymentName, workspaceConfigs[0].Name) + _, _ = fmt.Fprintf(out, "For example, try running:\n\n\t$ ssh %s%s\n", coderdConfig.HostnamePrefix, workspaceConfigs[0].Name) } else { _, _ = fmt.Fprint(out, "You don't have any workspaces yet, try creating one with:\n\n\t$ coder create \n") } diff --git a/cli/configssh_test.go b/cli/configssh_test.go index ca56bd7ff8e97..9e71ff323ad3f 100644 --- a/cli/configssh_test.go +++ b/cli/configssh_test.go @@ -69,7 +69,7 @@ func TestConfigSSH(t *testing.T) { client := coderdtest.New(t, &coderdtest.Options{ IncludeProvisionerDaemon: true, ConfigSSH: codersdk.CLISSHConfigResponse{ - DeploymentName: "test-coder", + HostnamePrefix: "test-coder", SSHConfigOptions: map[string]string{ // Something we can test for expectedKey: "3", diff --git a/cli/server.go b/cli/server.go index e5dd662037e50..7f2d293b1058f 100644 --- a/cli/server.go +++ b/cli/server.go @@ -702,7 +702,7 @@ flags, and YAML configuration. The precedence is as follows: FilesRateLimit: filesRateLimit, HTTPClient: httpClient, ConfigSSH: codersdk.CLISSHConfigResponse{ - DeploymentName: cfg.CLISSH.DeploymentName.String(), + HostnamePrefix: cfg.CLISSH.DeploymentName.String(), SSHConfigOptions: configSSHOptions, }, } diff --git a/coderd/coderd.go b/coderd/coderd.go index a0378f5954203..9fff8d747d21c 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -213,8 +213,8 @@ func New(options *Options) *API { if options.Auditor == nil { options.Auditor = audit.NewNop() } - if options.ConfigSSH.DeploymentName == "" { - options.ConfigSSH.DeploymentName = "coder" + if options.ConfigSSH.HostnamePrefix == "" { + options.ConfigSSH.HostnamePrefix = "coder." } // TODO: remove this once we promote authz_querier out of experiments. if experiments.Enabled(codersdk.ExperimentAuthzQuerier) { diff --git a/codersdk/deployment.go b/codersdk/deployment.go index 70ae71ea5107f..e95d0f27a9120 100644 --- a/codersdk/deployment.go +++ b/codersdk/deployment.go @@ -1307,15 +1307,15 @@ when required by your organization's security policy.`, Value: &c.Config, }, { - Name: "CLI SSH Deployment Name", + Name: "CLI SSH Hostname Prefix", Description: "The CLI SSH deployment name is the used in the Hostname of the ssh config.", - Flag: "cli-ssh-deployment-name", - Env: "CLI_SSH_DEPLOYMENT_NAME", - YAML: "cliSSHDeploymentName", + Flag: "cli-ssh-hostname-prefix", + Env: "CODER_SSH_HOSTNAME_PREFIX", + YAML: "cliSSHHostnamePrefix", Group: &deploymentGroupClient, Value: &c.CLISSH.DeploymentName, Hidden: false, - Default: "coder", + Default: "coder.", }, { Name: "CLI SSH Config Options", @@ -1646,7 +1646,7 @@ type DeploymentStats struct { } type CLISSHConfigResponse struct { - DeploymentName string `json:"deployment_name"` + HostnamePrefix string `json:"hostname_prefix"` SSHConfigOptions map[string]string `json:"ssh_config_options"` } From 7074f5052271d1d68f9b8ba7bba3ce22011edaf7 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 15 Mar 2023 15:04:53 -0500 Subject: [PATCH 14/34] CODER env prefix is automatic --- codersdk/deployment.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codersdk/deployment.go b/codersdk/deployment.go index e95d0f27a9120..1b10d48b2d254 100644 --- a/codersdk/deployment.go +++ b/codersdk/deployment.go @@ -1310,7 +1310,7 @@ when required by your organization's security policy.`, Name: "CLI SSH Hostname Prefix", Description: "The CLI SSH deployment name is the used in the Hostname of the ssh config.", Flag: "cli-ssh-hostname-prefix", - Env: "CODER_SSH_HOSTNAME_PREFIX", + Env: "SSH_HOSTNAME_PREFIX", YAML: "cliSSHHostnamePrefix", Group: &deploymentGroupClient, Value: &c.CLISSH.DeploymentName, From 952c591d9a51a4a8e36989553c9cc792476e24fa Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 15 Mar 2023 15:07:52 -0500 Subject: [PATCH 15/34] Renames --- cli/configssh_test.go | 2 +- cli/server.go | 2 +- coderd/clissh.go | 4 ++-- coderd/coderd.go | 16 +++++----------- coderd/coderdtest/coderdtest.go | 4 ++-- codersdk/deployment.go | 22 +++++++++++----------- 6 files changed, 22 insertions(+), 28 deletions(-) diff --git a/cli/configssh_test.go b/cli/configssh_test.go index 9e71ff323ad3f..2bf3a639e1d6a 100644 --- a/cli/configssh_test.go +++ b/cli/configssh_test.go @@ -68,7 +68,7 @@ func TestConfigSSH(t *testing.T) { const expectedKey = "ConnectionAttempts" client := coderdtest.New(t, &coderdtest.Options{ IncludeProvisionerDaemon: true, - ConfigSSH: codersdk.CLISSHConfigResponse{ + ConfigSSH: codersdk.SSHConfigResponse{ HostnamePrefix: "test-coder", SSHConfigOptions: map[string]string{ // Something we can test for diff --git a/cli/server.go b/cli/server.go index 7f2d293b1058f..c65874070f89c 100644 --- a/cli/server.go +++ b/cli/server.go @@ -701,7 +701,7 @@ flags, and YAML configuration. The precedence is as follows: LoginRateLimit: loginRateLimit, FilesRateLimit: filesRateLimit, HTTPClient: httpClient, - ConfigSSH: codersdk.CLISSHConfigResponse{ + SSHConfig: codersdk.SSHConfigResponse{ HostnamePrefix: cfg.CLISSH.DeploymentName.String(), SSHConfigOptions: configSSHOptions, }, diff --git a/coderd/clissh.go b/coderd/clissh.go index b75eec0c738eb..527202179c663 100644 --- a/coderd/clissh.go +++ b/coderd/clissh.go @@ -12,7 +12,7 @@ import ( // @Produce json // @Tags General // @Success 200 {object} codersdk.CLISSHConfigResponse -// @Router /config-ssh [get] +// @Router /deployment/ssh [get] func (a *API) cliSSHConfig(rw http.ResponseWriter, r *http.Request) { - httpapi.Write(r.Context(), rw, http.StatusOK, a.ConfigSSH) + httpapi.Write(r.Context(), rw, http.StatusOK, a.SSHConfig) } diff --git a/coderd/coderd.go b/coderd/coderd.go index 9fff8d747d21c..3abf8fd08df66 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -138,8 +138,8 @@ type Options struct { DeploymentValues *codersdk.DeploymentValues UpdateCheckOptions *updatecheck.Options // Set non-nil to enable update checking. - // ConfigSSH is the response clients use to configure config-ssh locally. - ConfigSSH codersdk.CLISSHConfigResponse + // SSHConfig is the response clients use to configure config-ssh locally. + SSHConfig codersdk.SSHConfigResponse HTTPClient *http.Client } @@ -213,8 +213,8 @@ func New(options *Options) *API { if options.Auditor == nil { options.Auditor = audit.NewNop() } - if options.ConfigSSH.HostnamePrefix == "" { - options.ConfigSSH.HostnamePrefix = "coder." + if options.SSHConfig.HostnamePrefix == "" { + options.SSHConfig.HostnamePrefix = "coder." } // TODO: remove this once we promote authz_querier out of experiments. if experiments.Enabled(codersdk.ExperimentAuthzQuerier) { @@ -405,17 +405,11 @@ func New(options *Options) *API { r.Post("/csp/reports", api.logReportCSPViolations) r.Get("/buildinfo", buildInfo) - r.Route("/config-ssh", func(r chi.Router) { - // Require auth for this route to prevent leaking the SSH config. - // to non-authenticated users. Also some config settings might - // be dependent on the user. - r.Use(apiKeyMiddleware) - r.Get("/", api.cliSSHConfig) - }) r.Route("/deployment", func(r chi.Router) { r.Use(apiKeyMiddleware) r.Get("/config", api.deploymentValues) r.Get("/stats", api.deploymentStats) + r.Get("/ssh", api.cliSSHConfig) }) r.Route("/experiments", func(r chi.Router) { r.Use(apiKeyMiddleware) diff --git a/coderd/coderdtest/coderdtest.go b/coderd/coderdtest/coderdtest.go index a04398dd72237..f0e7cc9711c22 100644 --- a/coderd/coderdtest/coderdtest.go +++ b/coderd/coderdtest/coderdtest.go @@ -126,7 +126,7 @@ type Options struct { Database database.Store Pubsub database.Pubsub - ConfigSSH codersdk.CLISSHConfigResponse + ConfigSSH codersdk.SSHConfigResponse SwaggerEndpoint bool } @@ -335,7 +335,7 @@ func NewOptions(t *testing.T, options *Options) (func(http.Handler), context.Can UpdateCheckOptions: options.UpdateCheckOptions, SwaggerEndpoint: options.SwaggerEndpoint, AppSigningKey: AppSigningKey, - ConfigSSH: options.ConfigSSH, + SSHConfig: options.ConfigSSH, } } diff --git a/codersdk/deployment.go b/codersdk/deployment.go index 1b10d48b2d254..f12bdcc9baf8d 100644 --- a/codersdk/deployment.go +++ b/codersdk/deployment.go @@ -1318,13 +1318,13 @@ when required by your organization's security policy.`, Default: "coder.", }, { - Name: "CLI SSH Config Options", - Description: "These cli config options will override the default ssh config options. " + + Name: "SSH Config Options", + Description: "These ssh config options will override the default ssh config options. " + "Provide options in key=value format separated by commas." + "Using this incorrectly can break ssh to your deployment. Use cautiously.", - Flag: "cli-ssh-options", - Env: "CLI_SSH_OPTIONS", - YAML: "cliSSHOptions", + Flag: "ssh-config-options", + Env: "SSH_CONFIG_OPTIONS", + YAML: "sshConfigOptions", Group: &deploymentGroupClient, Value: &c.CLISSH.SSHConfigOptions, Hidden: false, @@ -1645,24 +1645,24 @@ type DeploymentStats struct { SessionCount SessionCountDeploymentStats `json:"session_count"` } -type CLISSHConfigResponse struct { +type SSHConfigResponse struct { HostnamePrefix string `json:"hostname_prefix"` SSHConfigOptions map[string]string `json:"ssh_config_options"` } // SSHConfiguration returns information about the SSH configuration for the // Coder instance. -func (c *Client) SSHConfiguration(ctx context.Context) (CLISSHConfigResponse, error) { - res, err := c.Request(ctx, http.MethodGet, "/api/v2/config-ssh", nil) +func (c *Client) SSHConfiguration(ctx context.Context) (SSHConfigResponse, error) { + res, err := c.Request(ctx, http.MethodGet, "/api/v2/deployment/ssh", nil) if err != nil { - return CLISSHConfigResponse{}, err + return SSHConfigResponse{}, err } defer res.Body.Close() if res.StatusCode != http.StatusOK { - return CLISSHConfigResponse{}, ReadBodyAsError(res) + return SSHConfigResponse{}, ReadBodyAsError(res) } - var cliConfig CLISSHConfigResponse + var cliConfig SSHConfigResponse return cliConfig, json.NewDecoder(res.Body).Decode(&cliConfig) } From dae091ad3b976dc9d05d81413f22fb0611f7c8fb Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 15 Mar 2023 15:12:09 -0500 Subject: [PATCH 16/34] Make gen --- coderd/apidoc/docs.go | 78 +++++++++++++++++----------------- coderd/apidoc/swagger.json | 70 +++++++++++++++--------------- coderd/clissh.go | 2 +- docs/api/general.md | 70 +++++++++++++++--------------- docs/api/schemas.md | 40 ++++++++--------- site/src/api/typesGenerated.ts | 12 +++--- 6 files changed, 136 insertions(+), 136 deletions(-) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index bb9d899cdb263..29aadd7f9161a 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -304,31 +304,6 @@ const docTemplate = `{ } } }, - "/config-ssh": { - "get": { - "security": [ - { - "CoderSessionToken": [] - } - ], - "produces": [ - "application/json" - ], - "tags": [ - "General" - ], - "summary": "CLI SSH Config", - "operationId": "cli-ssh-config", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/codersdk.CLISSHConfigResponse" - } - } - } - } - }, "/csp/reports": { "post": { "security": [ @@ -409,6 +384,31 @@ const docTemplate = `{ } } }, + "/deployment/ssh": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "General" + ], + "summary": "CLI SSH Config", + "operationId": "cli-ssh-config", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.SSHConfigResponse" + } + } + } + } + }, "/deployment/stats": { "get": { "security": [ @@ -5979,20 +5979,6 @@ const docTemplate = `{ } } }, - "codersdk.CLISSHConfigResponse": { - "type": "object", - "properties": { - "deployment_name": { - "type": "string" - }, - "ssh_config_options": { - "type": "object", - "additionalProperties": { - "type": "string" - } - } - } - }, "codersdk.CreateFirstUserRequest": { "type": "object", "required": [ @@ -7712,6 +7698,20 @@ const docTemplate = `{ } } }, + "codersdk.SSHConfigResponse": { + "type": "object", + "properties": { + "hostname_prefix": { + "type": "string" + }, + "ssh_config_options": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, "codersdk.ServiceBannerConfig": { "type": "object", "properties": { diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 6301786b68fa2..67efff831acbe 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -258,27 +258,6 @@ } } }, - "/config-ssh": { - "get": { - "security": [ - { - "CoderSessionToken": [] - } - ], - "produces": ["application/json"], - "tags": ["General"], - "summary": "CLI SSH Config", - "operationId": "cli-ssh-config", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/codersdk.CLISSHConfigResponse" - } - } - } - } - }, "/csp/reports": { "post": { "security": [ @@ -347,6 +326,27 @@ } } }, + "/deployment/ssh": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": ["application/json"], + "tags": ["General"], + "summary": "CLI SSH Config", + "operationId": "cli-ssh-config", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.SSHConfigResponse" + } + } + } + } + }, "/deployment/stats": { "get": { "security": [ @@ -5327,20 +5327,6 @@ } } }, - "codersdk.CLISSHConfigResponse": { - "type": "object", - "properties": { - "deployment_name": { - "type": "string" - }, - "ssh_config_options": { - "type": "object", - "additionalProperties": { - "type": "string" - } - } - } - }, "codersdk.CreateFirstUserRequest": { "type": "object", "required": ["email", "password", "username"], @@ -6919,6 +6905,20 @@ } } }, + "codersdk.SSHConfigResponse": { + "type": "object", + "properties": { + "hostname_prefix": { + "type": "string" + }, + "ssh_config_options": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, "codersdk.ServiceBannerConfig": { "type": "object", "properties": { diff --git a/coderd/clissh.go b/coderd/clissh.go index 527202179c663..243b685722131 100644 --- a/coderd/clissh.go +++ b/coderd/clissh.go @@ -11,7 +11,7 @@ import ( // @Security CoderSessionToken // @Produce json // @Tags General -// @Success 200 {object} codersdk.CLISSHConfigResponse +// @Success 200 {object} codersdk.SSHConfigResponse // @Router /deployment/ssh [get] func (a *API) cliSSHConfig(rw http.ResponseWriter, r *http.Request) { httpapi.Write(r.Context(), rw, http.StatusOK, a.SSHConfig) diff --git a/docs/api/general.md b/docs/api/general.md index 7e5eb351e1c3a..8a0ef3d2e3e12 100644 --- a/docs/api/general.md +++ b/docs/api/general.md @@ -64,41 +64,6 @@ curl -X GET http://coder-server:8080/api/v2/buildinfo \ | ------ | ------------------------------------------------------- | ----------- | ------------------------------------------------------------------ | | 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.BuildInfoResponse](schemas.md#codersdkbuildinforesponse) | -## CLI SSH Config - -### Code samples - -```shell -# Example request using curl -curl -X GET http://coder-server:8080/api/v2/config-ssh \ - -H 'Accept: application/json' \ - -H 'Coder-Session-Token: API_KEY' -``` - -`GET /config-ssh` - -### Example responses - -> 200 Response - -```json -{ - "deployment_name": "string", - "ssh_config_options": { - "property1": "string", - "property2": "string" - } -} -``` - -### Responses - -| Status | Meaning | Description | Schema | -| ------ | ------------------------------------------------------- | ----------- | ------------------------------------------------------------------------ | -| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.CLISSHConfigResponse](schemas.md#codersdkclisshconfigresponse) | - -To perform this operation, you must be authenticated. [Learn more](authentication.md). - ## Report CSP violations ### Code samples @@ -437,6 +402,41 @@ curl -X GET http://coder-server:8080/api/v2/deployment/config \ To perform this operation, you must be authenticated. [Learn more](authentication.md). +## CLI SSH Config + +### Code samples + +```shell +# Example request using curl +curl -X GET http://coder-server:8080/api/v2/deployment/ssh \ + -H 'Accept: application/json' \ + -H 'Coder-Session-Token: API_KEY' +``` + +`GET /deployment/ssh` + +### Example responses + +> 200 Response + +```json +{ + "hostname_prefix": "string", + "ssh_config_options": { + "property1": "string", + "property2": "string" + } +} +``` + +### Responses + +| Status | Meaning | Description | Schema | +| ------ | ------------------------------------------------------- | ----------- | ------------------------------------------------------------------ | +| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.SSHConfigResponse](schemas.md#codersdksshconfigresponse) | + +To perform this operation, you must be authenticated. [Learn more](authentication.md). + ## Get deployment stats ### Code samples diff --git a/docs/api/schemas.md b/docs/api/schemas.md index 9fefe09b64dc6..1323f9e4f3ba0 100644 --- a/docs/api/schemas.md +++ b/docs/api/schemas.md @@ -1116,26 +1116,6 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in | `deploymentName` | string | false | | Deploymentname is the config-ssh Hostname prefix | | `sshconfigOptions` | array of string | false | | Sshconfigoptions are additional options to add to the ssh config file. This will override defaults. | -## codersdk.CLISSHConfigResponse - -```json -{ - "deployment_name": "string", - "ssh_config_options": { - "property1": "string", - "property2": "string" - } -} -``` - -### Properties - -| Name | Type | Required | Restrictions | Description | -| -------------------- | ------ | -------- | ------------ | ----------- | -| `deployment_name` | string | false | | | -| `ssh_config_options` | object | false | | | -| » `[any property]` | string | false | | | - ## codersdk.CreateFirstUserRequest ```json @@ -3363,6 +3343,26 @@ Parameter represents a set value for the scope. | `display_name` | string | false | | | | `name` | string | false | | | +## codersdk.SSHConfigResponse + +```json +{ + "hostname_prefix": "string", + "ssh_config_options": { + "property1": "string", + "property2": "string" + } +} +``` + +### Properties + +| Name | Type | Required | Restrictions | Description | +| -------------------- | ------ | -------- | ------------ | ----------- | +| `hostname_prefix` | string | false | | | +| `ssh_config_options` | object | false | | | +| » `[any property]` | string | false | | | + ## codersdk.ServiceBannerConfig ```json diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index e6cc03de08284..a98813b37253e 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -141,12 +141,6 @@ export interface CLISSHConfig { readonly SSHConfigOptions: string[] } -// From codersdk/deployment.go -export interface CLISSHConfigResponse { - readonly deployment_name: string - readonly ssh_config_options: Record -} - // From codersdk/parameters.go export interface ComputedParameter extends Parameter { readonly source_value: string @@ -680,6 +674,12 @@ export interface Role { readonly display_name: string } +// From codersdk/deployment.go +export interface SSHConfigResponse { + readonly hostname_prefix: string + readonly ssh_config_options: Record +} + // From codersdk/serversentevents.go export interface ServerSentEvent { readonly type: ServerSentEventType From a1dd7d491367626de52d65235aba3e33a0d7ba68 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 15 Mar 2023 15:23:55 -0500 Subject: [PATCH 17/34] Fix AutorizeAllEndpoints --- coderd/coderdtest/authorize.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coderd/coderdtest/authorize.go b/coderd/coderdtest/authorize.go index b83dcfa963f74..de6a333e98c5e 100644 --- a/coderd/coderdtest/authorize.go +++ b/coderd/coderdtest/authorize.go @@ -57,7 +57,7 @@ func AGPLRoutes(a *AuthTester) (map[string]string, map[string]RouteCheck) { "POST:/api/v2/csp/reports": {NoAuthorize: true}, "POST:/api/v2/authcheck": {NoAuthorize: true}, "GET:/api/v2/applications/host": {NoAuthorize: true}, - "GET:/api/v2/config-ssh": {NoAuthorize: true, StatusCode: http.StatusOK}, + "GET:/api/v2/deployment/ssh": {NoAuthorize: true, StatusCode: http.StatusOK}, // Has it's own auth "GET:/api/v2/users/oauth2/github/callback": {NoAuthorize: true}, From 4f426342859adebe2b802b6dd4483ac24de41f75 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 15 Mar 2023 15:31:09 -0500 Subject: [PATCH 18/34] Rename to drop 'CLI' --- cli/server.go | 6 +++--- coderd/apidoc/docs.go | 34 +++++++++++++++++----------------- coderd/apidoc/swagger.json | 34 +++++++++++++++++----------------- coderd/clissh.go | 18 ------------------ coderd/coderd.go | 2 +- coderd/deployment.go | 12 ++++++++++++ codersdk/deployment.go | 14 +++++++------- codersdk/deployment_test.go | 4 ++-- docs/api/schemas.md | 34 +++++++++++++++++----------------- site/src/api/typesGenerated.ts | 14 +++++++------- 10 files changed, 83 insertions(+), 89 deletions(-) delete mode 100644 coderd/clissh.go diff --git a/cli/server.go b/cli/server.go index c65874070f89c..db5b7ae09be82 100644 --- a/cli/server.go +++ b/cli/server.go @@ -672,9 +672,9 @@ flags, and YAML configuration. The precedence is as follows: return xerrors.Errorf("parse real ip config: %w", err) } - configSSHOptions, err := cfg.CLISSH.ParseOptions() + configSSHOptions, err := cfg.SSHConfig.ParseOptions() if err != nil { - return xerrors.Errorf("parse ssh config options %q: %w", cfg.CLISSH.SSHConfigOptions.String(), err) + return xerrors.Errorf("parse ssh config options %q: %w", cfg.SSHConfig.SSHConfigOptions.String(), err) } options := &coderd.Options{ @@ -702,7 +702,7 @@ flags, and YAML configuration. The precedence is as follows: FilesRateLimit: filesRateLimit, HTTPClient: httpClient, SSHConfig: codersdk.SSHConfigResponse{ - HostnamePrefix: cfg.CLISSH.DeploymentName.String(), + HostnamePrefix: cfg.SSHConfig.DeploymentName.String(), SSHConfigOptions: configSSHOptions, }, } diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 29aadd7f9161a..f0620548684e3 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -5963,22 +5963,6 @@ const docTemplate = `{ "BuildReasonAutostop" ] }, - "codersdk.CLISSHConfig": { - "type": "object", - "properties": { - "deploymentName": { - "description": "DeploymentName is the config-ssh Hostname prefix", - "type": "string" - }, - "sshconfigOptions": { - "description": "SSHConfigOptions are additional options to add to the ssh config file.\nThis will override defaults.", - "type": "array", - "items": { - "type": "string" - } - } - } - }, "codersdk.CreateFirstUserRequest": { "type": "object", "required": [ @@ -6579,7 +6563,7 @@ const docTemplate = `{ "type": "string" }, "cli_ssh": { - "$ref": "#/definitions/codersdk.CLISSHConfig" + "$ref": "#/definitions/codersdk.SSHConfig" }, "config": { "type": "string" @@ -7698,6 +7682,22 @@ const docTemplate = `{ } } }, + "codersdk.SSHConfig": { + "type": "object", + "properties": { + "deploymentName": { + "description": "DeploymentName is the config-ssh Hostname prefix", + "type": "string" + }, + "sshconfigOptions": { + "description": "SSHConfigOptions are additional options to add to the ssh config file.\nThis will override defaults.", + "type": "array", + "items": { + "type": "string" + } + } + } + }, "codersdk.SSHConfigResponse": { "type": "object", "properties": { diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 67efff831acbe..737306400c717 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -5311,22 +5311,6 @@ "BuildReasonAutostop" ] }, - "codersdk.CLISSHConfig": { - "type": "object", - "properties": { - "deploymentName": { - "description": "DeploymentName is the config-ssh Hostname prefix", - "type": "string" - }, - "sshconfigOptions": { - "description": "SSHConfigOptions are additional options to add to the ssh config file.\nThis will override defaults.", - "type": "array", - "items": { - "type": "string" - } - } - } - }, "codersdk.CreateFirstUserRequest": { "type": "object", "required": ["email", "password", "username"], @@ -5875,7 +5859,7 @@ "type": "string" }, "cli_ssh": { - "$ref": "#/definitions/codersdk.CLISSHConfig" + "$ref": "#/definitions/codersdk.SSHConfig" }, "config": { "type": "string" @@ -6905,6 +6889,22 @@ } } }, + "codersdk.SSHConfig": { + "type": "object", + "properties": { + "deploymentName": { + "description": "DeploymentName is the config-ssh Hostname prefix", + "type": "string" + }, + "sshconfigOptions": { + "description": "SSHConfigOptions are additional options to add to the ssh config file.\nThis will override defaults.", + "type": "array", + "items": { + "type": "string" + } + } + } + }, "codersdk.SSHConfigResponse": { "type": "object", "properties": { diff --git a/coderd/clissh.go b/coderd/clissh.go deleted file mode 100644 index 243b685722131..0000000000000 --- a/coderd/clissh.go +++ /dev/null @@ -1,18 +0,0 @@ -package coderd - -import ( - "net/http" - - "github.com/coder/coder/coderd/httpapi" -) - -// @Summary CLI SSH Config -// @ID cli-ssh-config -// @Security CoderSessionToken -// @Produce json -// @Tags General -// @Success 200 {object} codersdk.SSHConfigResponse -// @Router /deployment/ssh [get] -func (a *API) cliSSHConfig(rw http.ResponseWriter, r *http.Request) { - httpapi.Write(r.Context(), rw, http.StatusOK, a.SSHConfig) -} diff --git a/coderd/coderd.go b/coderd/coderd.go index 3abf8fd08df66..6e626aa742af4 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -409,7 +409,7 @@ func New(options *Options) *API { r.Use(apiKeyMiddleware) r.Get("/config", api.deploymentValues) r.Get("/stats", api.deploymentStats) - r.Get("/ssh", api.cliSSHConfig) + r.Get("/ssh", api.sshConfig) }) r.Route("/experiments", func(r chi.Router) { r.Use(apiKeyMiddleware) diff --git a/coderd/deployment.go b/coderd/deployment.go index 158b07c5bfbdd..0bbab80a26fb3 100644 --- a/coderd/deployment.go +++ b/coderd/deployment.go @@ -59,3 +59,15 @@ func (api *API) deploymentStats(rw http.ResponseWriter, r *http.Request) { httpapi.Write(r.Context(), rw, http.StatusOK, stats) } + + +// @Summary CLI SSH Config +// @ID cli-ssh-config +// @Security CoderSessionToken +// @Produce json +// @Tags General +// @Success 200 {object} codersdk.SSHConfigResponse +// @Router /deployment/ssh [get] +func (a *API) sshConfig(rw http.ResponseWriter, r *http.Request) { + httpapi.Write(r.Context(), rw, http.StatusOK, a.SSHConfig) +} diff --git a/codersdk/deployment.go b/codersdk/deployment.go index f12bdcc9baf8d..7a83b0b61bc50 100644 --- a/codersdk/deployment.go +++ b/codersdk/deployment.go @@ -161,7 +161,7 @@ type DeploymentValues struct { DisablePasswordAuth clibase.Bool `json:"disable_password_auth,omitempty" typescript:",notnull"` Support SupportConfig `json:"support,omitempty" typescript:",notnull"` GitAuthProviders clibase.Struct[[]GitAuthConfig] `json:"git_auth,omitempty" typescript:",notnull"` - CLISSH CLISSHConfig `json:"cli_ssh,omitempty" typescript:",notnull"` + SSHConfig SSHConfig `json:"cli_ssh,omitempty" typescript:",notnull"` Config clibase.String `json:"config,omitempty" typescript:",notnull"` WriteConfig clibase.Bool `json:"write_config,omitempty" typescript:",notnull"` @@ -170,9 +170,9 @@ type DeploymentValues struct { Address clibase.HostPort `json:"address,omitempty" typescript:",notnull"` } -// CLISSHConfig is configuration the cli & vscode extension use for configuring +// SSHConfig is configuration the cli & vscode extension use for configuring // ssh connections. -type CLISSHConfig struct { +type SSHConfig struct { // DeploymentName is the config-ssh Hostname prefix DeploymentName clibase.String // SSHConfigOptions are additional options to add to the ssh config file. @@ -180,7 +180,7 @@ type CLISSHConfig struct { SSHConfigOptions clibase.Strings } -func (c CLISSHConfig) ParseOptions() (map[string]string, error) { +func (c SSHConfig) ParseOptions() (map[string]string, error) { m := make(map[string]string) for _, opt := range c.SSHConfigOptions { key, value, err := ParseSSHConfigOption(opt) @@ -1311,9 +1311,9 @@ when required by your organization's security policy.`, Description: "The CLI SSH deployment name is the used in the Hostname of the ssh config.", Flag: "cli-ssh-hostname-prefix", Env: "SSH_HOSTNAME_PREFIX", - YAML: "cliSSHHostnamePrefix", + YAML: "sshHostnamePrefix", Group: &deploymentGroupClient, - Value: &c.CLISSH.DeploymentName, + Value: &c.SSHConfig.DeploymentName, Hidden: false, Default: "coder.", }, @@ -1326,7 +1326,7 @@ when required by your organization's security policy.`, Env: "SSH_CONFIG_OPTIONS", YAML: "sshConfigOptions", Group: &deploymentGroupClient, - Value: &c.CLISSH.SSHConfigOptions, + Value: &c.SSHConfig.SSHConfigOptions, Hidden: false, }, { diff --git a/codersdk/deployment_test.go b/codersdk/deployment_test.go index 59060b6d9efe2..c29a7a5cfdb5b 100644 --- a/codersdk/deployment_test.go +++ b/codersdk/deployment_test.go @@ -109,7 +109,7 @@ func TestDeploymentValues_HighlyConfigurable(t *testing.T) { } } -func TestCLISSHConfig_ParseOptions(t *testing.T) { +func TestSSHConfig_ParseOptions(t *testing.T) { t.Parallel() testCases := []struct { @@ -174,7 +174,7 @@ func TestCLISSHConfig_ParseOptions(t *testing.T) { tt := tt t.Run(tt.Name, func(t *testing.T) { t.Parallel() - c := codersdk.CLISSHConfig{ + c := codersdk.SSHConfig{ SSHConfigOptions: tt.ConfigOptions, } got, err := c.ParseOptions() diff --git a/docs/api/schemas.md b/docs/api/schemas.md index 1323f9e4f3ba0..17df8e5010618 100644 --- a/docs/api/schemas.md +++ b/docs/api/schemas.md @@ -1100,22 +1100,6 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in | `autostart` | | `autostop` | -## codersdk.CLISSHConfig - -```json -{ - "deploymentName": "string", - "sshconfigOptions": ["string"] -} -``` - -### Properties - -| Name | Type | Required | Restrictions | Description | -| ------------------ | --------------- | -------- | ------------ | --------------------------------------------------------------------------------------------------- | -| `deploymentName` | string | false | | Deploymentname is the config-ssh Hostname prefix | -| `sshconfigOptions` | array of string | false | | Sshconfigoptions are additional options to add to the ssh config file. This will override defaults. | - ## codersdk.CreateFirstUserRequest ```json @@ -2261,7 +2245,7 @@ CreateParameterRequest is a structure used to create a new parameter value for a | `autobuild_poll_interval` | integer | false | | | | `browser_only` | boolean | false | | | | `cache_directory` | string | false | | | -| `cli_ssh` | [codersdk.CLISSHConfig](#codersdkclisshconfig) | false | | | +| `cli_ssh` | [codersdk.SSHConfig](#codersdksshconfig) | false | | | | `config` | string | false | | | | `dangerous` | [codersdk.DangerousConfig](#codersdkdangerousconfig) | false | | | | `derp` | [codersdk.DERP](#codersdkderp) | false | | | @@ -3343,6 +3327,22 @@ Parameter represents a set value for the scope. | `display_name` | string | false | | | | `name` | string | false | | | +## codersdk.SSHConfig + +```json +{ + "deploymentName": "string", + "sshconfigOptions": ["string"] +} +``` + +### Properties + +| Name | Type | Required | Restrictions | Description | +| ------------------ | --------------- | -------- | ------------ | --------------------------------------------------------------------------------------------------- | +| `deploymentName` | string | false | | Deploymentname is the config-ssh Hostname prefix | +| `sshconfigOptions` | array of string | false | | Sshconfigoptions are additional options to add to the ssh config file. This will override defaults. | + ## codersdk.SSHConfigResponse ```json diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index a98813b37253e..ec4535fec848a 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -135,12 +135,6 @@ export interface BuildInfoResponse { readonly version: string } -// From codersdk/deployment.go -export interface CLISSHConfig { - readonly DeploymentName: string - readonly SSHConfigOptions: string[] -} - // From codersdk/parameters.go export interface ComputedParameter extends Parameter { readonly source_value: string @@ -365,7 +359,7 @@ export interface DeploymentValues { // Named type "github.com/coder/coder/cli/clibase.Struct[[]github.com/coder/coder/codersdk.GitAuthConfig]" unknown, using "any" // eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO explain why this is needed readonly git_auth?: any - readonly cli_ssh?: CLISSHConfig + readonly cli_ssh?: SSHConfig readonly config?: string readonly write_config?: boolean // Named type "github.com/coder/coder/cli/clibase.HostPort" unknown, using "any" @@ -674,6 +668,12 @@ export interface Role { readonly display_name: string } +// From codersdk/deployment.go +export interface SSHConfig { + readonly DeploymentName: string + readonly SSHConfigOptions: string[] +} + // From codersdk/deployment.go export interface SSHConfigResponse { readonly hostname_prefix: string From c218edd9b5b75f0f4de5fe3682a1772b5b4669c8 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 15 Mar 2023 15:32:07 -0500 Subject: [PATCH 19/34] Prefix requires . --- cli/configssh_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/configssh_test.go b/cli/configssh_test.go index 2bf3a639e1d6a..cad37d835d8ca 100644 --- a/cli/configssh_test.go +++ b/cli/configssh_test.go @@ -69,7 +69,7 @@ func TestConfigSSH(t *testing.T) { client := coderdtest.New(t, &coderdtest.Options{ IncludeProvisionerDaemon: true, ConfigSSH: codersdk.SSHConfigResponse{ - HostnamePrefix: "test-coder", + HostnamePrefix: "test-coder.", SSHConfigOptions: map[string]string{ // Something we can test for expectedKey: "3", From a752fc80a36963d6f0f2df12ddf2d5420bd813b2 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 15 Mar 2023 15:32:46 -0500 Subject: [PATCH 20/34] Use constant in test --- cli/configssh_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cli/configssh_test.go b/cli/configssh_test.go index cad37d835d8ca..13d36a1efed53 100644 --- a/cli/configssh_test.go +++ b/cli/configssh_test.go @@ -64,12 +64,12 @@ func sshConfigFileRead(t *testing.T, name string) string { func TestConfigSSH(t *testing.T) { t.Parallel() - const hostname = "test-coder" + const hostname = "test-coder." const expectedKey = "ConnectionAttempts" client := coderdtest.New(t, &coderdtest.Options{ IncludeProvisionerDaemon: true, ConfigSSH: codersdk.SSHConfigResponse{ - HostnamePrefix: "test-coder.", + HostnamePrefix: hostname, SSHConfigOptions: map[string]string{ // Something we can test for expectedKey: "3", @@ -199,7 +199,7 @@ func TestConfigSSH(t *testing.T) { home := filepath.Dir(filepath.Dir(sshConfigFile)) // #nosec - sshCmd := exec.Command("ssh", "-F", sshConfigFile, hostname+"."+workspace.Name, "echo", "test") + sshCmd := exec.Command("ssh", "-F", sshConfigFile, hostname+workspace.Name, "echo", "test") pty = ptytest.New(t) // Set HOME because coder config is included from ~/.ssh/coder. sshCmd.Env = append(sshCmd.Env, fmt.Sprintf("HOME=%s", home)) From d328d97cd297437be36eafeede196f82710ebc33 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 15 Mar 2023 15:44:39 -0500 Subject: [PATCH 21/34] Linting --- coderd/deployment.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/coderd/deployment.go b/coderd/deployment.go index 0bbab80a26fb3..1ad1282ce46d0 100644 --- a/coderd/deployment.go +++ b/coderd/deployment.go @@ -60,7 +60,6 @@ func (api *API) deploymentStats(rw http.ResponseWriter, r *http.Request) { httpapi.Write(r.Context(), rw, http.StatusOK, stats) } - // @Summary CLI SSH Config // @ID cli-ssh-config // @Security CoderSessionToken @@ -68,6 +67,6 @@ func (api *API) deploymentStats(rw http.ResponseWriter, r *http.Request) { // @Tags General // @Success 200 {object} codersdk.SSHConfigResponse // @Router /deployment/ssh [get] -func (a *API) sshConfig(rw http.ResponseWriter, r *http.Request) { - httpapi.Write(r.Context(), rw, http.StatusOK, a.SSHConfig) +func (api *API) sshConfig(rw http.ResponseWriter, r *http.Request) { + httpapi.Write(r.Context(), rw, http.StatusOK, api.SSHConfig) } From a4b9620fb2478d29bf503515ad13cb3333d875aa Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 15 Mar 2023 16:26:11 -0500 Subject: [PATCH 22/34] Formatting --- codersdk/deployment.go | 4 ++-- codersdk/deployment_test.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/codersdk/deployment.go b/codersdk/deployment.go index 7a83b0b61bc50..2179e378b1ec3 100644 --- a/codersdk/deployment.go +++ b/codersdk/deployment.go @@ -1663,6 +1663,6 @@ func (c *Client) SSHConfiguration(ctx context.Context) (SSHConfigResponse, error return SSHConfigResponse{}, ReadBodyAsError(res) } - var cliConfig SSHConfigResponse - return cliConfig, json.NewDecoder(res.Body).Decode(&cliConfig) + var sshConfig SSHConfigResponse + return sshConfig, json.NewDecoder(res.Body).Decode(&sshConfig) } diff --git a/codersdk/deployment_test.go b/codersdk/deployment_test.go index c29a7a5cfdb5b..8f1e3de930d09 100644 --- a/codersdk/deployment_test.go +++ b/codersdk/deployment_test.go @@ -3,9 +3,9 @@ package codersdk_test import ( "testing" - "github.com/coder/coder/cli/clibase" "github.com/stretchr/testify/require" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/codersdk" ) From 78fbda80adffd595b133171b32c3aecc07f12cb6 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 16 Mar 2023 10:09:43 -0500 Subject: [PATCH 23/34] Allow the user to override the host prefix --- cli/configssh.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cli/configssh.go b/cli/configssh.go index d527eb6bf4cc7..b114db9992820 100644 --- a/cli/configssh.go +++ b/cli/configssh.go @@ -71,7 +71,6 @@ func (o *sshConfigOptions) addOption(option string) error { // Override existing option if they share the same key. // This is case-insensitive. Parsing each time might be a little slow, // but it is ok. - // existingKey, _, err := codersdk.ParseSSHConfigOption(existing) if err != nil { // Don't mess with original values if there is an error. @@ -178,6 +177,7 @@ func configSSH() *cobra.Command { usePreviousOpts bool dryRun bool skipProxyCommand bool + userHostPrefix string ) cmd := &cobra.Command{ Annotations: workspaceCommand, @@ -336,6 +336,11 @@ func configSSH() *cobra.Command { coderdConfig.HostnamePrefix = "coder." } + if userHostPrefix != "" { + // Override with user flag. + coderdConfig.HostnamePrefix = userHostPrefix + } + // Ensure stable sorting of output. slices.SortFunc(workspaceConfigs, func(a, b sshWorkspaceConfig) bool { return a.Name < b.Name @@ -468,6 +473,7 @@ func configSSH() *cobra.Command { cmd.Flags().BoolVarP(&skipProxyCommand, "skip-proxy-command", "", false, "Specifies whether the ProxyCommand option should be skipped. Useful for testing.") _ = cmd.Flags().MarkHidden("skip-proxy-command") cliflag.BoolVarP(cmd.Flags(), &usePreviousOpts, "use-previous-options", "", "CODER_SSH_USE_PREVIOUS_OPTIONS", false, "Specifies whether or not to keep options from previous run of config-ssh.") + cmd.Flags().StringVarP(&userHostPrefix, "ssh-host-prefix", "", "", "Override the default host prefix.") cliui.AllowSkipPrompt(cmd) return cmd From d28b850af5d4cd9fe57411068b35cafacc548613 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 16 Mar 2023 10:12:47 -0500 Subject: [PATCH 24/34] Fix doc messages --- codersdk/deployment.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/codersdk/deployment.go b/codersdk/deployment.go index 2179e378b1ec3..340ed81a2ffd0 100644 --- a/codersdk/deployment.go +++ b/codersdk/deployment.go @@ -1307,9 +1307,9 @@ when required by your organization's security policy.`, Value: &c.Config, }, { - Name: "CLI SSH Hostname Prefix", - Description: "The CLI SSH deployment name is the used in the Hostname of the ssh config.", - Flag: "cli-ssh-hostname-prefix", + Name: "SSH Host Prefix", + Description: "The SSH deployment prefix is used in the Host of the ssh config.", + Flag: "ssh-hostname-prefix", Env: "SSH_HOSTNAME_PREFIX", YAML: "sshHostnamePrefix", Group: &deploymentGroupClient, @@ -1319,9 +1319,9 @@ when required by your organization's security policy.`, }, { Name: "SSH Config Options", - Description: "These ssh config options will override the default ssh config options. " + - "Provide options in key=value format separated by commas." + - "Using this incorrectly can break ssh to your deployment. Use cautiously.", + Description: "These SSH config options will override the default SSH config options. " + + "Provide options in \"key=value\" or \"key value\" format separated by commas." + + "Using this incorrectly can break SSH to your deployment, use cautiously.", Flag: "ssh-config-options", Env: "SSH_CONFIG_OPTIONS", YAML: "sshConfigOptions", From 617d987ec56bf5317f181d8e3912c322b301021e Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 16 Mar 2023 10:19:59 -0500 Subject: [PATCH 25/34] Make gen --- cli/configssh.go | 6 +++--- docs/cli/coder_config-ssh.md | 7 +++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/cli/configssh.go b/cli/configssh.go index b114db9992820..cb1befa67c018 100644 --- a/cli/configssh.go +++ b/cli/configssh.go @@ -348,8 +348,8 @@ func configSSH() *cobra.Command { for _, wc := range workspaceConfigs { sort.Strings(wc.Hosts) // Write agent configuration. - for _, hostname := range wc.Hosts { - sshHostname := fmt.Sprintf("%s%s", coderdConfig.HostnamePrefix, hostname) + for _, workspaceHostname := range wc.Hosts { + sshHostname := fmt.Sprintf("%s%s", coderdConfig.HostnamePrefix, workspaceHostname) var configOptions sshConfigOptions // Add standard options. err := configOptions.addOptions( @@ -370,7 +370,7 @@ func configSSH() *cobra.Command { if !skipProxyCommand { err := configOptions.addOptions(fmt.Sprintf( "ProxyCommand %s --global-config %s ssh --stdio %s", - escapedCoderBinary, escapedGlobalConfig, hostname, + escapedCoderBinary, escapedGlobalConfig, workspaceHostname, )) if err != nil { return err diff --git a/docs/cli/coder_config-ssh.md b/docs/cli/coder_config-ssh.md index ca5c55f688adb..a1943e93af990 100644 --- a/docs/cli/coder_config-ssh.md +++ b/docs/cli/coder_config-ssh.md @@ -42,6 +42,13 @@ Specifies the path to an SSH config. | Consumes | $CODER_SSH_CONFIG_FILE | | Default | ~/.ssh/config | +### --ssh-host-prefix + +Override the default host prefix. +
+| | | +| --- | --- | + ### --ssh-option, -o Specifies additional SSH options to embed in each host stanza. From eb4bb7be42a0f2639d06c57bf93b13ace56f23b7 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 16 Mar 2023 10:20:41 -0500 Subject: [PATCH 26/34] Fix comment --- cli/configssh.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/configssh.go b/cli/configssh.go index cb1befa67c018..8db3c58701c5d 100644 --- a/cli/configssh.go +++ b/cli/configssh.go @@ -49,7 +49,7 @@ type sshConfigOptions struct { sshOptions []string } -// add expects an option in the form of "option=value" or "option value". +// addOptions expects options in the form of "option=value" or "option value". // It will override any existing option with the same key to prevent duplicates. // Invalid options will return an error. func (o *sshConfigOptions) addOptions(options ...string) error { From 123ce024caf867db6595d34d29ba6b1698017e87 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 16 Mar 2023 10:23:24 -0500 Subject: [PATCH 27/34] Remove "CLI" part of naming --- coderd/apidoc/docs.go | 4 ++-- coderd/apidoc/swagger.json | 4 ++-- coderd/deployment.go | 4 ++-- codersdk/deployment.go | 2 +- docs/api/general.md | 2 +- site/src/api/typesGenerated.ts | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index f0620548684e3..3e70017b1b981 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -397,8 +397,8 @@ const docTemplate = `{ "tags": [ "General" ], - "summary": "CLI SSH Config", - "operationId": "cli-ssh-config", + "summary": "SSH Config", + "operationId": "ssh-config", "responses": { "200": { "description": "OK", diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 737306400c717..49583dd9f789b 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -335,8 +335,8 @@ ], "produces": ["application/json"], "tags": ["General"], - "summary": "CLI SSH Config", - "operationId": "cli-ssh-config", + "summary": "SSH Config", + "operationId": "ssh-config", "responses": { "200": { "description": "OK", diff --git a/coderd/deployment.go b/coderd/deployment.go index 1ad1282ce46d0..78ed31bc4f1b0 100644 --- a/coderd/deployment.go +++ b/coderd/deployment.go @@ -60,8 +60,8 @@ func (api *API) deploymentStats(rw http.ResponseWriter, r *http.Request) { httpapi.Write(r.Context(), rw, http.StatusOK, stats) } -// @Summary CLI SSH Config -// @ID cli-ssh-config +// @Summary SSH Config +// @ID ssh-config // @Security CoderSessionToken // @Produce json // @Tags General diff --git a/codersdk/deployment.go b/codersdk/deployment.go index 340ed81a2ffd0..8b822219cde96 100644 --- a/codersdk/deployment.go +++ b/codersdk/deployment.go @@ -161,7 +161,7 @@ type DeploymentValues struct { DisablePasswordAuth clibase.Bool `json:"disable_password_auth,omitempty" typescript:",notnull"` Support SupportConfig `json:"support,omitempty" typescript:",notnull"` GitAuthProviders clibase.Struct[[]GitAuthConfig] `json:"git_auth,omitempty" typescript:",notnull"` - SSHConfig SSHConfig `json:"cli_ssh,omitempty" typescript:",notnull"` + SSHConfig SSHConfig `json:"config_ssh,omitempty" typescript:",notnull"` Config clibase.String `json:"config,omitempty" typescript:",notnull"` WriteConfig clibase.Bool `json:"write_config,omitempty" typescript:",notnull"` diff --git a/docs/api/general.md b/docs/api/general.md index 8a0ef3d2e3e12..eb3a3d5bc010a 100644 --- a/docs/api/general.md +++ b/docs/api/general.md @@ -402,7 +402,7 @@ curl -X GET http://coder-server:8080/api/v2/deployment/config \ To perform this operation, you must be authenticated. [Learn more](authentication.md). -## CLI SSH Config +## SSH Config ### Code samples diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index ec4535fec848a..24f4e2010a58f 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -359,7 +359,7 @@ export interface DeploymentValues { // Named type "github.com/coder/coder/cli/clibase.Struct[[]github.com/coder/coder/codersdk.GitAuthConfig]" unknown, using "any" // eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO explain why this is needed readonly git_auth?: any - readonly cli_ssh?: SSHConfig + readonly config_ssh?: SSHConfig readonly config?: string readonly write_config?: boolean // Named type "github.com/coder/coder/cli/clibase.HostPort" unknown, using "any" From ca41ccebd115215dc3606c74a98028c432f9286a Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 16 Mar 2023 11:34:37 -0500 Subject: [PATCH 28/34] Update golden files --- cli/testdata/coder_config-ssh_--help.golden | 1 + helm/tests/testdata/default_values.golden | 12 ++++++------ helm/tests/testdata/tls.golden | 12 ++++++------ 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/cli/testdata/coder_config-ssh_--help.golden b/cli/testdata/coder_config-ssh_--help.golden index b088c8586bc5b..1fe06b04be12c 100644 --- a/cli/testdata/coder_config-ssh_--help.golden +++ b/cli/testdata/coder_config-ssh_--help.golden @@ -19,6 +19,7 @@ Flags: -h, --help help for config-ssh --ssh-config-file string Specifies the path to an SSH config. Consumes $CODER_SSH_CONFIG_FILE (default "~/.ssh/config") + --ssh-host-prefix string Override the default host prefix. -o, --ssh-option stringArray Specifies additional SSH options to embed in each host stanza. --use-previous-options Specifies whether or not to keep options from previous run of config-ssh. diff --git a/helm/tests/testdata/default_values.golden b/helm/tests/testdata/default_values.golden index cf5e342e1408b..49087c05f4c65 100644 --- a/helm/tests/testdata/default_values.golden +++ b/helm/tests/testdata/default_values.golden @@ -9,7 +9,7 @@ metadata: labels: helm.sh/chart: coder-0.1.0 app.kubernetes.io/name: coder - app.kubernetes.io/instance: release-name + app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/part-of: coder app.kubernetes.io/version: "0.1.0" app.kubernetes.io/managed-by: Helm @@ -48,7 +48,7 @@ metadata: labels: helm.sh/chart: coder-0.1.0 app.kubernetes.io/name: coder - app.kubernetes.io/instance: release-name + app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/part-of: coder app.kubernetes.io/version: "0.1.0" app.kubernetes.io/managed-by: Helm @@ -65,7 +65,7 @@ spec: externalTrafficPolicy: "Cluster" selector: app.kubernetes.io/name: coder - app.kubernetes.io/instance: release-name + app.kubernetes.io/instance: RELEASE-NAME --- # Source: coder/templates/coder.yaml apiVersion: apps/v1 @@ -75,7 +75,7 @@ metadata: labels: helm.sh/chart: coder-0.1.0 app.kubernetes.io/name: coder - app.kubernetes.io/instance: release-name + app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/part-of: coder app.kubernetes.io/version: "0.1.0" app.kubernetes.io/managed-by: Helm @@ -86,13 +86,13 @@ spec: selector: matchLabels: app.kubernetes.io/name: coder - app.kubernetes.io/instance: release-name + app.kubernetes.io/instance: RELEASE-NAME template: metadata: labels: helm.sh/chart: coder-0.1.0 app.kubernetes.io/name: coder - app.kubernetes.io/instance: release-name + app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/part-of: coder app.kubernetes.io/version: "0.1.0" app.kubernetes.io/managed-by: Helm diff --git a/helm/tests/testdata/tls.golden b/helm/tests/testdata/tls.golden index ff2773e3d5bda..cfadea7e6fa9c 100644 --- a/helm/tests/testdata/tls.golden +++ b/helm/tests/testdata/tls.golden @@ -9,7 +9,7 @@ metadata: labels: helm.sh/chart: coder-0.1.0 app.kubernetes.io/name: coder - app.kubernetes.io/instance: release-name + app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/part-of: coder app.kubernetes.io/version: "0.1.0" app.kubernetes.io/managed-by: Helm @@ -48,7 +48,7 @@ metadata: labels: helm.sh/chart: coder-0.1.0 app.kubernetes.io/name: coder - app.kubernetes.io/instance: release-name + app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/part-of: coder app.kubernetes.io/version: "0.1.0" app.kubernetes.io/managed-by: Helm @@ -69,7 +69,7 @@ spec: externalTrafficPolicy: "Cluster" selector: app.kubernetes.io/name: coder - app.kubernetes.io/instance: release-name + app.kubernetes.io/instance: RELEASE-NAME --- # Source: coder/templates/coder.yaml apiVersion: apps/v1 @@ -79,7 +79,7 @@ metadata: labels: helm.sh/chart: coder-0.1.0 app.kubernetes.io/name: coder - app.kubernetes.io/instance: release-name + app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/part-of: coder app.kubernetes.io/version: "0.1.0" app.kubernetes.io/managed-by: Helm @@ -90,13 +90,13 @@ spec: selector: matchLabels: app.kubernetes.io/name: coder - app.kubernetes.io/instance: release-name + app.kubernetes.io/instance: RELEASE-NAME template: metadata: labels: helm.sh/chart: coder-0.1.0 app.kubernetes.io/name: coder - app.kubernetes.io/instance: release-name + app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/part-of: coder app.kubernetes.io/version: "0.1.0" app.kubernetes.io/managed-by: Helm From efcbc2966753a43e5bb1c89cfbd55be7aed8e75f Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 16 Mar 2023 11:41:30 -0500 Subject: [PATCH 29/34] Fix 404 logic --- cli/configssh.go | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/cli/configssh.go b/cli/configssh.go index 8db3c58701c5d..fdfd8e156a3bd 100644 --- a/cli/configssh.go +++ b/cli/configssh.go @@ -321,16 +321,10 @@ func configSSH() *cobra.Command { if err != nil { // If the error is 404, this deployment does not support // this endpoint yet. Do not error, just assume defaults. - // TODO: Remove this in 2 months (May 2023). Just return the error + // TODO: Remove this in 2 months (May 31, 2023). Just return the error // and remove this 404 check. var sdkErr *codersdk.Error - if !xerrors.As(err, &sdkErr) { - // not an SDK error, return the original error. - return xerrors.Errorf("fetch coderd config failed: %w", err) - } - - if sdkErr.StatusCode() != http.StatusNotFound { - // Not a 404, return the original error. + if !(xerrors.As(err, &sdkErr) && sdkErr.StatusCode() == http.StatusNotFound) { return xerrors.Errorf("fetch coderd config failed: %w", err) } coderdConfig.HostnamePrefix = "coder." From 3c1c87f45cbe1ec6deea3e127d2b4cb0155aa774 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 16 Mar 2023 11:44:02 -0500 Subject: [PATCH 30/34] remove 1 error check --- cli/configssh.go | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/cli/configssh.go b/cli/configssh.go index fdfd8e156a3bd..71d6e45107988 100644 --- a/cli/configssh.go +++ b/cli/configssh.go @@ -344,10 +344,8 @@ func configSSH() *cobra.Command { // Write agent configuration. for _, workspaceHostname := range wc.Hosts { sshHostname := fmt.Sprintf("%s%s", coderdConfig.HostnamePrefix, workspaceHostname) - var configOptions sshConfigOptions - // Add standard options. - err := configOptions.addOptions( - "HostName "+sshHostname, + defaultOptions := []string{ + "HostName " + sshHostname, "ConnectTimeout=0", "StrictHostKeyChecking=no", // Without this, the "REMOTE HOST IDENTITY CHANGED" @@ -356,19 +354,20 @@ func configSSH() *cobra.Command { // This disables the "Warning: Permanently added 'hostname' (RSA) to the list of known hosts." // message from appearing on every SSH. This happens because we ignore the known hosts. "LogLevel ERROR", - ) - if err != nil { - return err } if !skipProxyCommand { - err := configOptions.addOptions(fmt.Sprintf( + defaultOptions = append(defaultOptions, fmt.Sprintf( "ProxyCommand %s --global-config %s ssh --stdio %s", escapedCoderBinary, escapedGlobalConfig, workspaceHostname, )) - if err != nil { - return err - } + } + + var configOptions sshConfigOptions + // Add standard options. + err := configOptions.addOptions(defaultOptions...) + if err != nil { + return err } // Override with deployment options From 4586b11b1cf4156ba72c69d968f89dc2cbea0adf Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 16 Mar 2023 11:45:11 -0500 Subject: [PATCH 31/34] Move buildinfo into deployment.go --- coderd/buildinfo.go | 22 ---------------------- coderd/deployment.go | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 22 deletions(-) delete mode 100644 coderd/buildinfo.go diff --git a/coderd/buildinfo.go b/coderd/buildinfo.go deleted file mode 100644 index 76497f8990e8a..0000000000000 --- a/coderd/buildinfo.go +++ /dev/null @@ -1,22 +0,0 @@ -package coderd - -import ( - "net/http" - - "github.com/coder/coder/buildinfo" - "github.com/coder/coder/coderd/httpapi" - "github.com/coder/coder/codersdk" -) - -// @Summary Build info -// @ID build-info -// @Produce json -// @Tags General -// @Success 200 {object} codersdk.BuildInfoResponse -// @Router /buildinfo [get] -func buildInfo(rw http.ResponseWriter, r *http.Request) { - httpapi.Write(r.Context(), rw, http.StatusOK, codersdk.BuildInfoResponse{ - ExternalURL: buildinfo.ExternalURL(), - Version: buildinfo.Version(), - }) -} diff --git a/coderd/deployment.go b/coderd/deployment.go index 78ed31bc4f1b0..83556dde0c091 100644 --- a/coderd/deployment.go +++ b/coderd/deployment.go @@ -1,6 +1,7 @@ package coderd import ( + "github.com/coder/coder/buildinfo" "net/http" "github.com/coder/coder/coderd/httpapi" @@ -60,6 +61,20 @@ func (api *API) deploymentStats(rw http.ResponseWriter, r *http.Request) { httpapi.Write(r.Context(), rw, http.StatusOK, stats) } +// @Summary Build info +// @ID build-info +// @Produce json +// @Tags General +// @Success 200 {object} codersdk.BuildInfoResponse +// @Router /buildinfo [get] +func buildInfo(rw http.ResponseWriter, r *http.Request) { + httpapi.Write(r.Context(), rw, http.StatusOK, codersdk.BuildInfoResponse{ + ExternalURL: buildinfo.ExternalURL(), + Version: buildinfo.Version(), + }) +} + + // @Summary SSH Config // @ID ssh-config // @Security CoderSessionToken From 0f2ef97d089b435bcd1e070bdc31e69d659c1c2c Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 16 Mar 2023 11:45:32 -0500 Subject: [PATCH 32/34] fixup! Move buildinfo into deployment.go --- coderd/deployment.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/coderd/deployment.go b/coderd/deployment.go index 83556dde0c091..e9cb55c270c11 100644 --- a/coderd/deployment.go +++ b/coderd/deployment.go @@ -1,9 +1,9 @@ package coderd import ( - "github.com/coder/coder/buildinfo" "net/http" + "github.com/coder/coder/buildinfo" "github.com/coder/coder/coderd/httpapi" "github.com/coder/coder/coderd/rbac" "github.com/coder/coder/codersdk" @@ -74,7 +74,6 @@ func buildInfo(rw http.ResponseWriter, r *http.Request) { }) } - // @Summary SSH Config // @ID ssh-config // @Security CoderSessionToken From a5aac50929c376278f71f6d551e25dc43b47f06a Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 16 Mar 2023 11:57:30 -0500 Subject: [PATCH 33/34] make gen --- coderd/apidoc/docs.go | 6 +++--- coderd/apidoc/swagger.json | 6 +++--- docs/api/general.md | 4 ++-- docs/api/schemas.md | 10 +++++----- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 3e70017b1b981..062423f9cef91 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -6562,12 +6562,12 @@ const docTemplate = `{ "cache_directory": { "type": "string" }, - "cli_ssh": { - "$ref": "#/definitions/codersdk.SSHConfig" - }, "config": { "type": "string" }, + "config_ssh": { + "$ref": "#/definitions/codersdk.SSHConfig" + }, "dangerous": { "$ref": "#/definitions/codersdk.DangerousConfig" }, diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 49583dd9f789b..db43c036df2fc 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -5858,12 +5858,12 @@ "cache_directory": { "type": "string" }, - "cli_ssh": { - "$ref": "#/definitions/codersdk.SSHConfig" - }, "config": { "type": "string" }, + "config_ssh": { + "$ref": "#/definitions/codersdk.SSHConfig" + }, "dangerous": { "$ref": "#/definitions/codersdk.DangerousConfig" }, diff --git a/docs/api/general.md b/docs/api/general.md index eb3a3d5bc010a..e687a71945264 100644 --- a/docs/api/general.md +++ b/docs/api/general.md @@ -154,11 +154,11 @@ curl -X GET http://coder-server:8080/api/v2/deployment/config \ "autobuild_poll_interval": 0, "browser_only": true, "cache_directory": "string", - "cli_ssh": { + "config": "string", + "config_ssh": { "deploymentName": "string", "sshconfigOptions": ["string"] }, - "config": "string", "dangerous": { "allow_path_app_sharing": true, "allow_path_app_site_owner_access": true diff --git a/docs/api/schemas.md b/docs/api/schemas.md index 17df8e5010618..887080bc42134 100644 --- a/docs/api/schemas.md +++ b/docs/api/schemas.md @@ -1686,11 +1686,11 @@ CreateParameterRequest is a structure used to create a new parameter value for a "autobuild_poll_interval": 0, "browser_only": true, "cache_directory": "string", - "cli_ssh": { + "config": "string", + "config_ssh": { "deploymentName": "string", "sshconfigOptions": ["string"] }, - "config": "string", "dangerous": { "allow_path_app_sharing": true, "allow_path_app_site_owner_access": true @@ -2030,11 +2030,11 @@ CreateParameterRequest is a structure used to create a new parameter value for a "autobuild_poll_interval": 0, "browser_only": true, "cache_directory": "string", - "cli_ssh": { + "config": "string", + "config_ssh": { "deploymentName": "string", "sshconfigOptions": ["string"] }, - "config": "string", "dangerous": { "allow_path_app_sharing": true, "allow_path_app_site_owner_access": true @@ -2245,8 +2245,8 @@ CreateParameterRequest is a structure used to create a new parameter value for a | `autobuild_poll_interval` | integer | false | | | | `browser_only` | boolean | false | | | | `cache_directory` | string | false | | | -| `cli_ssh` | [codersdk.SSHConfig](#codersdksshconfig) | false | | | | `config` | string | false | | | +| `config_ssh` | [codersdk.SSHConfig](#codersdksshconfig) | false | | | | `dangerous` | [codersdk.DangerousConfig](#codersdkdangerousconfig) | false | | | | `derp` | [codersdk.DERP](#codersdkderp) | false | | | | `disable_password_auth` | boolean | false | | | From a3254cdc815a5c8d5bd293a68b55bf43882e7e2d Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 16 Mar 2023 16:58:32 +0000 Subject: [PATCH 34/34] Golden files --- helm/tests/testdata/default_values.golden | 12 ++++++------ helm/tests/testdata/tls.golden | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/helm/tests/testdata/default_values.golden b/helm/tests/testdata/default_values.golden index 49087c05f4c65..cf5e342e1408b 100644 --- a/helm/tests/testdata/default_values.golden +++ b/helm/tests/testdata/default_values.golden @@ -9,7 +9,7 @@ metadata: labels: helm.sh/chart: coder-0.1.0 app.kubernetes.io/name: coder - app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/instance: release-name app.kubernetes.io/part-of: coder app.kubernetes.io/version: "0.1.0" app.kubernetes.io/managed-by: Helm @@ -48,7 +48,7 @@ metadata: labels: helm.sh/chart: coder-0.1.0 app.kubernetes.io/name: coder - app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/instance: release-name app.kubernetes.io/part-of: coder app.kubernetes.io/version: "0.1.0" app.kubernetes.io/managed-by: Helm @@ -65,7 +65,7 @@ spec: externalTrafficPolicy: "Cluster" selector: app.kubernetes.io/name: coder - app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/instance: release-name --- # Source: coder/templates/coder.yaml apiVersion: apps/v1 @@ -75,7 +75,7 @@ metadata: labels: helm.sh/chart: coder-0.1.0 app.kubernetes.io/name: coder - app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/instance: release-name app.kubernetes.io/part-of: coder app.kubernetes.io/version: "0.1.0" app.kubernetes.io/managed-by: Helm @@ -86,13 +86,13 @@ spec: selector: matchLabels: app.kubernetes.io/name: coder - app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/instance: release-name template: metadata: labels: helm.sh/chart: coder-0.1.0 app.kubernetes.io/name: coder - app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/instance: release-name app.kubernetes.io/part-of: coder app.kubernetes.io/version: "0.1.0" app.kubernetes.io/managed-by: Helm diff --git a/helm/tests/testdata/tls.golden b/helm/tests/testdata/tls.golden index cfadea7e6fa9c..ff2773e3d5bda 100644 --- a/helm/tests/testdata/tls.golden +++ b/helm/tests/testdata/tls.golden @@ -9,7 +9,7 @@ metadata: labels: helm.sh/chart: coder-0.1.0 app.kubernetes.io/name: coder - app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/instance: release-name app.kubernetes.io/part-of: coder app.kubernetes.io/version: "0.1.0" app.kubernetes.io/managed-by: Helm @@ -48,7 +48,7 @@ metadata: labels: helm.sh/chart: coder-0.1.0 app.kubernetes.io/name: coder - app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/instance: release-name app.kubernetes.io/part-of: coder app.kubernetes.io/version: "0.1.0" app.kubernetes.io/managed-by: Helm @@ -69,7 +69,7 @@ spec: externalTrafficPolicy: "Cluster" selector: app.kubernetes.io/name: coder - app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/instance: release-name --- # Source: coder/templates/coder.yaml apiVersion: apps/v1 @@ -79,7 +79,7 @@ metadata: labels: helm.sh/chart: coder-0.1.0 app.kubernetes.io/name: coder - app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/instance: release-name app.kubernetes.io/part-of: coder app.kubernetes.io/version: "0.1.0" app.kubernetes.io/managed-by: Helm @@ -90,13 +90,13 @@ spec: selector: matchLabels: app.kubernetes.io/name: coder - app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/instance: release-name template: metadata: labels: helm.sh/chart: coder-0.1.0 app.kubernetes.io/name: coder - app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/instance: release-name app.kubernetes.io/part-of: coder app.kubernetes.io/version: "0.1.0" app.kubernetes.io/managed-by: Helm