sshtheater: check for Include line in ~/.ssh/config
diff --git a/dockerimg/dockerimg.go b/dockerimg/dockerimg.go
index a92fb92..976a979 100644
--- a/dockerimg/dockerimg.go
+++ b/dockerimg/dockerimg.go
@@ -259,22 +259,30 @@
return appendInternalErr(fmt.Errorf("Error splitting ssh host and port: %w", err))
}
- cst, err := NewSSHTheather(cntrName, sshHost, sshPort)
- if err != nil {
- return appendInternalErr(fmt.Errorf("NewContainerSSHTheather: %w", err))
- }
+ var sshServerIdentity, sshUserIdentity []byte
- fmt.Printf(`Connect to this container via any of these methods:
+ if err := CheckForInclude(); err != nil {
+ fmt.Println(err.Error())
+ // continue - ssh config is not required for the rest of sketch to function locally.
+ } else {
+ cst, err := NewSSHTheather(cntrName, sshHost, sshPort)
+ if err != nil {
+ return appendInternalErr(fmt.Errorf("NewContainerSSHTheather: %w", err))
+ }
+
+ fmt.Printf(`Connect to this container via any of these methods:
🖥️ ssh %s
🖥️ code --remote ssh-remote+root@%s /app -n
🔗 vscode://vscode-remote/ssh-remote+root@%s/app?n=true
`, cntrName, cntrName, cntrName)
-
- defer func() {
- if err := cst.Cleanup(); err != nil {
- appendInternalErr(err)
- }
- }()
+ sshUserIdentity = cst.userIdentity
+ sshServerIdentity = cst.serverIdentity
+ defer func() {
+ if err := cst.Cleanup(); err != nil {
+ appendInternalErr(err)
+ }
+ }()
+ }
// Tell the sketch container which git server port and commit to initialize with.
go func() {
@@ -283,7 +291,7 @@
// the scrollback (which is not good, but also not fatal). I can't see why it does this
// though, since none of the calls in postContainerInitConfig obviously write to stdout
// or stderr.
- if err := postContainerInitConfig(ctx, localAddr, commit, gitSrv.gitPort, gitSrv.pass, cst.serverIdentity, cst.userIdentity); err != nil {
+ if err := postContainerInitConfig(ctx, localAddr, commit, gitSrv.gitPort, gitSrv.pass, sshServerIdentity, sshUserIdentity); err != nil {
slog.ErrorContext(ctx, "LaunchContainer.postContainerInitConfig", slog.String("err", err.Error()))
errCh <- appendInternalErr(err)
}
diff --git a/dockerimg/sshtheater.go b/dockerimg/sshtheater.go
index 35433dd..53a8383 100644
--- a/dockerimg/sshtheater.go
+++ b/dockerimg/sshtheater.go
@@ -110,6 +110,38 @@
return cst, nil
}
+func CheckForInclude() error {
+ sketchSSHPathInclude := "Include " + filepath.Join(os.Getenv("HOME"), ".sketch", "ssh_config")
+ defaultSSHPath := filepath.Join(os.Getenv("HOME"), ".ssh", "config")
+ f, _ := os.Open(filepath.Join(os.Getenv("HOME"), ".ssh", "config"))
+ cfg, _ := ssh_config.Decode(f)
+ var sketchInludePos *ssh_config.Position
+ var firstNonIncludePos *ssh_config.Position
+ for _, host := range cfg.Hosts {
+ for _, node := range host.Nodes {
+ inc, ok := node.(*ssh_config.Include)
+ if ok {
+ if strings.TrimSpace(inc.String()) == sketchSSHPathInclude {
+ pos := inc.Pos()
+ sketchInludePos = &pos
+ }
+ } else if firstNonIncludePos == nil && !strings.HasPrefix(strings.TrimSpace(node.String()), "#") {
+ pos := node.Pos()
+ firstNonIncludePos = &pos
+ }
+ }
+ }
+
+ if sketchInludePos == nil {
+ return fmt.Errorf("⚠️ SSH connections are disabled. To enable them, add the line %q to the top of %s before any 'Host' lines", sketchSSHPathInclude, defaultSSHPath)
+ }
+
+ if firstNonIncludePos != nil && firstNonIncludePos.Line < sketchInludePos.Line {
+ fmt.Printf("⚠️ SSH confg warning: The location of the Include statement for sketch's ssh config on line %d of %s may prevent ssh from working with sketch containers. Try moving it to the top of the file (before any 'Host' lines) if ssh isn't working for you.\n", sketchInludePos.Line, defaultSSHPath)
+ }
+ return nil
+}
+
func removeFromHosts(cntrName string, cfgHosts []*ssh_config.Host) []*ssh_config.Host {
hosts := []*ssh_config.Host{}
for _, host := range cfgHosts {