package ssh import ( "context" "errors" "fmt" "os" "testing" "time" "charm.land/log/v2" "charm.land/ssh" bm "charm.land/wish/v2/bubbletea" "charm.land/wish/v2/testsession" "github.com/charmbracelet/soft-serve/pkg/backend" "github.com/charmbracelet/soft-serve/pkg/config" "github.com/charmbracelet/soft-serve/pkg/db" "github.com/charmbracelet/soft-serve/pkg/db/migrate" "github.com/charmbracelet/soft-serve/pkg/store" "github.com/charmbracelet/soft-serve/pkg/store/database" "github.com/charmbracelet/soft-serve/pkg/test" "github.com/matryer/is" gossh "golang.org/x/crypto/ssh" _ "modernc.org/sqlite" // sqlite driver ) func TestSession(t *testing.T) { is := is.New(t) t.Run("authorized repo access", func(t *testing.T) { t.Log("setting up") s, close := setup(t) s.Stderr = os.Stderr t.Log("requesting pty") err := s.RequestPty("xterm", 80, 40, nil) is.NoErr(err) go func() { time.Sleep(1 * time.Second) // s.Signal(gossh.SIGTERM) s.Close() //nolint: errcheck }() t.Log("waiting for session to exit") _, err = s.Output("test") var ee *gossh.ExitMissingError is.True(errors.As(err, &ee)) t.Log("session exited") is.NoErr(close()) }) } func setup(tb testing.TB) (*gossh.Session, func() error) { tb.Helper() is := is.New(tb) dp := tb.TempDir() is.NoErr(os.Setenv("SOFT_SERVE_DATA_PATH", dp)) is.NoErr(os.Setenv("SOFT_SERVE_GIT_LISTEN_ADDR", ":9418")) is.NoErr(os.Setenv("SOFT_SERVE_SSH_LISTEN_ADDR", fmt.Sprintf(":%d", test.RandomPort()))) tb.Cleanup(func() { is.NoErr(os.Unsetenv("SOFT_SERVE_DATA_PATH")) is.NoErr(os.Unsetenv("SOFT_SERVE_GIT_LISTEN_ADDR")) is.NoErr(os.Unsetenv("SOFT_SERVE_SSH_LISTEN_ADDR")) is.NoErr(os.RemoveAll(dp)) }) ctx := context.TODO() cfg := config.DefaultConfig() if err := cfg.Validate(); err != nil { log.Fatal(err) } ctx = config.WithContext(ctx, cfg) dbx, err := db.Open(ctx, cfg.DB.Driver, cfg.DB.DataSource) if err != nil { tb.Fatal(err) } if err := migrate.Migrate(ctx, dbx); err != nil { tb.Fatal(err) } dbstore := database.New(ctx, dbx) ctx = store.WithContext(ctx, dbstore) be := backend.New(ctx, cfg, dbx, dbstore) return testsession.New(tb, &ssh.Server{ Handler: ContextMiddleware(cfg, dbx, dbstore, be, log.Default())(bm.MiddlewareWithProgramHandler(SessionHandler)(func(s ssh.Session) { _, _, active := s.Pty() if !active { os.Exit(1) } s.Exit(0) })), }, nil), dbx.Close }