1package ssh
2
3import (
4 "context"
5 "errors"
6 "fmt"
7 "os"
8 "testing"
9 "time"
10
11 log "github.com/charmbracelet/log/v2"
12 "github.com/charmbracelet/soft-serve/pkg/backend"
13 "github.com/charmbracelet/soft-serve/pkg/config"
14 "github.com/charmbracelet/soft-serve/pkg/db"
15 "github.com/charmbracelet/soft-serve/pkg/db/migrate"
16 "github.com/charmbracelet/soft-serve/pkg/store"
17 "github.com/charmbracelet/soft-serve/pkg/store/database"
18 "github.com/charmbracelet/soft-serve/pkg/test"
19 "github.com/charmbracelet/ssh"
20 bm "github.com/charmbracelet/wish/v2/bubbletea"
21 "github.com/charmbracelet/wish/v2/testsession"
22 "github.com/matryer/is"
23 gossh "golang.org/x/crypto/ssh"
24 _ "modernc.org/sqlite" // sqlite driver
25)
26
27func TestSession(t *testing.T) {
28 is := is.New(t)
29 t.Run("authorized repo access", func(t *testing.T) {
30 t.Log("setting up")
31 s, cleanup := setup(t)
32 s.Stderr = os.Stderr
33 t.Log("requesting pty")
34 err := s.RequestPty("xterm", 80, 40, nil)
35 is.NoErr(err)
36 go func() {
37 time.Sleep(1 * time.Second)
38 // s.Signal(gossh.SIGTERM)
39 s.Close() //nolint: errcheck
40 }()
41 t.Log("waiting for session to exit")
42 _, err = s.Output("test")
43 var ee *gossh.ExitMissingError
44 is.True(errors.As(err, &ee))
45 t.Log("session exited")
46 is.NoErr(cleanup())
47 })
48}
49
50func setup(tb testing.TB) (*gossh.Session, func() error) {
51 tb.Helper()
52 is := is.New(tb)
53 dp := tb.TempDir()
54 is.NoErr(os.Setenv("SOFT_SERVE_DATA_PATH", dp))
55 is.NoErr(os.Setenv("SOFT_SERVE_GIT_LISTEN_ADDR", ":9418"))
56 is.NoErr(os.Setenv("SOFT_SERVE_SSH_LISTEN_ADDR", fmt.Sprintf(":%d", test.RandomPort())))
57 tb.Cleanup(func() {
58 is.NoErr(os.Unsetenv("SOFT_SERVE_DATA_PATH"))
59 is.NoErr(os.Unsetenv("SOFT_SERVE_GIT_LISTEN_ADDR"))
60 is.NoErr(os.Unsetenv("SOFT_SERVE_SSH_LISTEN_ADDR"))
61 is.NoErr(os.RemoveAll(dp))
62 })
63 ctx := context.TODO()
64 cfg := config.DefaultConfig()
65 if err := cfg.Validate(); err != nil {
66 log.Fatal(err)
67 }
68 ctx = config.WithContext(ctx, cfg)
69 dbx, err := db.Open(ctx, cfg.DB.Driver, cfg.DB.DataSource)
70 if err != nil {
71 tb.Fatal(err)
72 }
73 if err := migrate.Migrate(ctx, dbx); err != nil {
74 tb.Fatal(err)
75 }
76 dbstore := database.New(ctx, dbx)
77 ctx = store.WithContext(ctx, dbstore)
78 be := backend.New(ctx, cfg, dbx, dbstore)
79 ctx = backend.WithContext(ctx, be)
80 return testsession.New(tb, &ssh.Server{
81 Handler: ContextMiddleware(cfg, dbx, dbstore, be, log.Default())(bm.MiddlewareWithProgramHandler(SessionHandler)(func(s ssh.Session) {
82 _, _, active := s.Pty()
83 if !active {
84 os.Exit(1)
85 }
86 s.Exit(0)
87 })),
88 }, nil), dbx.Close
89}