1package ssh
2
3import (
4 "context"
5 "errors"
6 "fmt"
7 "log"
8 "os"
9 "testing"
10 "time"
11
12 "github.com/charmbracelet/soft-serve/server/backend/sqlite"
13 "github.com/charmbracelet/soft-serve/server/config"
14 "github.com/charmbracelet/soft-serve/server/test"
15 "github.com/charmbracelet/ssh"
16 bm "github.com/charmbracelet/wish/bubbletea"
17 "github.com/charmbracelet/wish/testsession"
18 "github.com/matryer/is"
19 "github.com/muesli/termenv"
20 gossh "golang.org/x/crypto/ssh"
21)
22
23func TestSession(t *testing.T) {
24 is := is.New(t)
25 t.Run("authorized repo access", func(t *testing.T) {
26 t.Log("setting up")
27 s, close := setup(t)
28 s.Stderr = os.Stderr
29 t.Log("requesting pty")
30 err := s.RequestPty("xterm", 80, 40, nil)
31 is.NoErr(err)
32 go func() {
33 time.Sleep(1 * time.Second)
34 s.Signal(gossh.SIGTERM)
35 // FIXME: exit with code 0 instead of forcibly closing the session
36 s.Close()
37 }()
38 t.Log("waiting for session to exit")
39 _, err = s.Output("test")
40 var ee *gossh.ExitMissingError
41 is.True(errors.As(err, &ee))
42 t.Log("session exited")
43 _ = close()
44 })
45}
46
47func setup(tb testing.TB) (*gossh.Session, func() error) {
48 tb.Helper()
49 is := is.New(tb)
50 dp := tb.TempDir()
51 is.NoErr(os.Setenv("SOFT_SERVE_DATA_PATH", dp))
52 is.NoErr(os.Setenv("SOFT_SERVE_GIT_LISTEN_ADDR", ":9418"))
53 is.NoErr(os.Setenv("SOFT_SERVE_SSH_LISTEN_ADDR", fmt.Sprintf(":%d", test.RandomPort())))
54 tb.Cleanup(func() {
55 is.NoErr(os.Unsetenv("SOFT_SERVE_DATA_PATH"))
56 is.NoErr(os.Unsetenv("SOFT_SERVE_GIT_LISTEN_ADDR"))
57 is.NoErr(os.Unsetenv("SOFT_SERVE_SSH_LISTEN_ADDR"))
58 is.NoErr(os.RemoveAll(dp))
59 })
60 ctx := context.TODO()
61 cfg := config.DefaultConfig()
62 ctx = config.WithContext(ctx, cfg)
63 fb, err := sqlite.NewSqliteBackend(ctx)
64 if err != nil {
65 log.Fatal(err)
66 }
67 cfg = cfg.WithBackend(fb)
68 return testsession.New(tb, &ssh.Server{
69 Handler: bm.MiddlewareWithProgramHandler(SessionHandler(cfg), termenv.ANSI256)(func(s ssh.Session) {
70 _, _, active := s.Pty()
71 if !active {
72 os.Exit(1)
73 }
74 s.Exit(0)
75 }),
76 }, nil), fb.Close
77}