@@ -20,14 +20,14 @@ require (
require (
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be
github.com/aymanbagabas/git-module v1.8.4-0.20231101154130-8d27204ac6d2
- github.com/aymanbagabas/go-pty v0.2.0
+ github.com/aymanbagabas/go-pty v0.2.1
github.com/caarlos0/duration v0.0.0-20220103233809-8df7c22fe305
github.com/caarlos0/env/v10 v10.0.0
github.com/caarlos0/tablewriter v0.1.0
github.com/charmbracelet/git-lfs-transfer v0.1.1-0.20231027181609-f7ff6baf2ed0
github.com/charmbracelet/keygen v0.5.0
github.com/charmbracelet/log v0.3.1
- github.com/charmbracelet/ssh v0.0.0-20231129225614-669b249ca6ee
+ github.com/charmbracelet/ssh v0.0.0-20231203183338-c29875a2932c
github.com/go-jose/go-jose/v3 v3.0.1
github.com/gobwas/glob v0.2.3
github.com/golang-jwt/jwt/v5 v5.1.0
@@ -16,8 +16,8 @@ github.com/aymanbagabas/git-module v1.8.4-0.20231101154130-8d27204ac6d2/go.mod h
github.com/aymanbagabas/go-osc52 v1.0.3/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
-github.com/aymanbagabas/go-pty v0.2.0 h1:fC2ATGqFG+zH0Hr0Ks46h0lrRU2ExmQxR7iHUjBG1Do=
-github.com/aymanbagabas/go-pty v0.2.0/go.mod h1:Ul2Zd4Z3Cby9ByGdurtjlAafh6pjgrjiHNAsx4LC5yE=
+github.com/aymanbagabas/go-pty v0.2.1 h1:bqnC0bCkr4OAQ1fZdqqriRzGnZTHC71wogGNOPjSNHQ=
+github.com/aymanbagabas/go-pty v0.2.1/go.mod h1:1EXZe9k53iaw8QnevpvYenkDazponD+qtcp1s1E7CsQ=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/beevik/ntp v0.3.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg=
@@ -51,8 +51,8 @@ github.com/charmbracelet/lipgloss v0.9.1 h1:PNyd3jvaJbg4jRHKWXnCj1akQm4rh8dbEzN1
github.com/charmbracelet/lipgloss v0.9.1/go.mod h1:1mPmG4cxScwUQALAAnacHaigiiHB9Pmr+v1VEawJl6I=
github.com/charmbracelet/log v0.3.1 h1:TjuY4OBNbxmHWSwO3tosgqs5I3biyY8sQPny/eCMTYw=
github.com/charmbracelet/log v0.3.1/go.mod h1:OR4E1hutLsax3ZKpXbgUqPtTjQfrh1pG3zwHGWuuq8g=
-github.com/charmbracelet/ssh v0.0.0-20231129225614-669b249ca6ee h1:r0yd6qZE8iLT2smnxiYre41b9/atj4kFxsfuIXW0Oqs=
-github.com/charmbracelet/ssh v0.0.0-20231129225614-669b249ca6ee/go.mod h1:Lq6b5f587hn2S27yNPgSB4Nei+iqOkghe9Ep7syGuQY=
+github.com/charmbracelet/ssh v0.0.0-20231203183338-c29875a2932c h1:ylmTNGYtwoe8Dfl5piAxQOrzBOnYtjnY4C+aAHXcoVU=
+github.com/charmbracelet/ssh v0.0.0-20231203183338-c29875a2932c/go.mod h1:PzGIpBYAWrMVea9T6tpJiIHm7Z/Hpnm7WTfOTkZ63xc=
github.com/charmbracelet/wish v1.2.0 h1:h5Wj9pr97IQz/l4gM5Xep2lXcY/YM+6O2RC2o3x0JIQ=
github.com/charmbracelet/wish v1.2.0/go.mod h1:JX3fC+178xadJYAhPu6qWtVDpJTwpnFvpdjz9RKJlUE=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
@@ -2,11 +2,8 @@ package shell
import (
"context"
- "errors"
"fmt"
"io"
- "io/fs"
- "os"
"os/exec"
"path/filepath"
@@ -141,9 +138,10 @@ func startCommand(co *cobra.Command, args []string) error {
cmdPath := filepath.Join(cmdsDir, args[0])
- if stat, err := os.Stat(cmdPath); errors.Is(err, fs.ErrNotExist) || stat.Mode()&0111 == 0 {
- return fmt.Errorf("command not found: %s", args[0])
- }
+ // if stat, err := os.Stat(cmdPath); errors.Is(err, fs.ErrNotExist) || stat.Mode()&0111 == 0 {
+ // log.Printf("command mode %s", stat.Mode().String())
+ // return fmt.Errorf("command not found: %s", args[0])
+ // }
cmdPath, err := filepath.Abs(cmdPath)
if err != nil {
@@ -2,55 +2,60 @@ package ssh
import (
"fmt"
- "io"
+ "os"
+ "os/exec"
+ "strings"
"github.com/charmbracelet/log"
- "github.com/charmbracelet/soft-serve/pkg/shell"
"github.com/charmbracelet/ssh"
"github.com/charmbracelet/wish"
)
// ShellMiddleware is a middleware for the SSH shell.
func ShellMiddleware(sh ssh.Handler) ssh.Handler {
+ softBin, err := os.Executable()
+ if err != nil {
+ // TODO: handle this better
+ panic(err)
+ }
+
return func(s ssh.Session) {
ctx := s.Context()
logger := log.FromContext(ctx).WithPrefix("ssh")
- envs := &sessionEnv{s}
-
- ppty, _, isInteractive := s.Pty()
-
- var (
- in io.Reader = s
- out io.Writer = s
- er io.Writer = s.Stderr()
- err error
- )
-
- if isInteractive {
- in, out, er, err = ptyNew(ppty.Pty)
- if err != nil {
- logger.Errorf("could not create pty: %v", err)
- // TODO: replace this err with a declared error
- wish.Fatalln(s, fmt.Errorf("internal server error"))
- return
- }
- }
args := s.Command()
- if len(args) == 0 {
- // XXX: args cannot be nil, otherwise cobra will use os.Args[1:]
- args = []string{}
+ ppty, winch, isInteractive := s.Pty()
+
+ envs := s.Environ()
+ if len(args) > 0 {
+ envs = append(envs, "SSH_ORIGINAL_COMMAND="+strings.Join(args, " "))
}
- cmd := shell.Command(ctx, envs, isInteractive)
- cmd.SetArgs(args)
- cmd.SetIn(in)
- cmd.SetOut(out)
- cmd.SetErr(er)
- cmd.SetContext(ctx)
+ var cmd interface {
+ Run() error
+ }
+ cmdArgs := []string{"shell", "-c", fmt.Sprintf("'%s'", strings.Join(args, " "))}
+ if isInteractive && ppty.Pty != nil {
+ ppty.Pty.Resize(ppty.Window.Width, ppty.Window.Height)
+ go func() {
+ for win := range winch {
+ log.Printf("resizing to %d x %d", win.Width, win.Height)
+ ppty.Pty.Resize(win.Width, win.Height)
+ }
+ }()
+
+ c := ppty.Pty.CommandContext(ctx, softBin, cmdArgs...)
+ c.Env = append(envs, "PATH="+os.Getenv("PATH"))
+ cmd = c
+ } else {
+ c := exec.CommandContext(ctx, softBin, cmdArgs...)
+ c.Env = append(envs, "PATH="+os.Getenv("PATH"))
+ cmd = c
+ }
- if err := cmd.ExecuteContext(ctx); err != nil {
- wish.Fatalln(s, err)
+ if err := cmd.Run(); err != nil {
+ logger.Errorf("error running command: %s", err)
+ wish.Fatal(s, "internal server error")
return
}