server/server_test.go 🔗
@@ -99,7 +99,9 @@ func setupServer(t *testing.T) *Server {
go func() {
s.Start()
}()
- defer s.Close()
+ t.Cleanup(func() {
+ s.Close()
+ })
return s
}
Ayman Bagabas created
Prevent unauthorized ui access to private repos.
Fixes: https://github.com/charmbracelet/soft-serve/issues/189
server/server_test.go | 4 +
server/session.go | 8 ++++
server/session_test.go | 77 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 88 insertions(+), 1 deletion(-)
@@ -99,7 +99,9 @@ func setupServer(t *testing.T) *Server {
go func() {
s.Start()
}()
- defer s.Close()
+ t.Cleanup(func() {
+ s.Close()
+ })
return s
}
@@ -6,11 +6,14 @@ import (
"github.com/aymanbagabas/go-osc52"
tea "github.com/charmbracelet/bubbletea"
appCfg "github.com/charmbracelet/soft-serve/config"
+ cm "github.com/charmbracelet/soft-serve/server/cmd"
"github.com/charmbracelet/soft-serve/ui"
"github.com/charmbracelet/soft-serve/ui/common"
"github.com/charmbracelet/soft-serve/ui/keymap"
"github.com/charmbracelet/soft-serve/ui/styles"
+ "github.com/charmbracelet/wish"
bm "github.com/charmbracelet/wish/bubbletea"
+ gm "github.com/charmbracelet/wish/git"
"github.com/gliderlabs/ssh"
zone "github.com/lrstanley/bubblezone"
)
@@ -26,6 +29,11 @@ func SessionHandler(ac *appCfg.Config) bm.ProgramHandler {
initialRepo := ""
if len(cmd) == 1 {
initialRepo = cmd[0]
+ auth := ac.AuthRepo(initialRepo, s.PublicKey())
+ if auth < gm.ReadOnlyAccess {
+ wish.Fatalln(s, cm.ErrUnauthorized)
+ return nil
+ }
}
if ac.Cfg.Callbacks != nil {
ac.Cfg.Callbacks.Tui("new session")
@@ -0,0 +1,77 @@
+package server
+
+import (
+ "bytes"
+ "errors"
+ "os"
+ "strings"
+ "testing"
+ "time"
+
+ appCfg "github.com/charmbracelet/soft-serve/config"
+ cm "github.com/charmbracelet/soft-serve/server/cmd"
+ "github.com/charmbracelet/soft-serve/server/config"
+ bm "github.com/charmbracelet/wish/bubbletea"
+ "github.com/charmbracelet/wish/testsession"
+ "github.com/gliderlabs/ssh"
+ "github.com/matryer/is"
+ "github.com/muesli/termenv"
+ gossh "golang.org/x/crypto/ssh"
+)
+
+func TestSession(t *testing.T) {
+ is := is.New(t)
+ t.Run("unauthorized repo access", func(t *testing.T) {
+ var out bytes.Buffer
+ s := setup(t)
+ s.Stderr = &out
+ defer s.Close()
+ err := s.RequestPty("xterm", 80, 40, nil)
+ is.NoErr(err)
+ err = s.Run("config")
+ // Session writes error and exits
+ is.True(strings.Contains(out.String(), cm.ErrUnauthorized.Error()))
+ var ee *gossh.ExitError
+ is.True(errors.As(err, &ee) && ee.ExitStatus() == 1)
+ })
+ t.Run("authorized repo access", func(t *testing.T) {
+ s := setup(t)
+ s.Stderr = os.Stderr
+ defer s.Close()
+ err := s.RequestPty("xterm", 80, 40, nil)
+ is.NoErr(err)
+ go func() {
+ time.Sleep(1 * time.Second)
+ s.Signal(gossh.SIGTERM)
+ // FIXME: exit with code 0 instead of forcibly closing the session
+ s.Close()
+ }()
+ err = s.Run("test")
+ var ee *gossh.ExitMissingError
+ is.True(errors.As(err, &ee))
+ })
+}
+
+func setup(tb testing.TB) *gossh.Session {
+ is := is.New(tb)
+ tb.Helper()
+ cfg.RepoPath = tb.TempDir()
+ ac, err := appCfg.NewConfig(&config.Config{
+ Port: 22226,
+ KeyPath: tb.TempDir(),
+ RepoPath: tb.TempDir(),
+ InitialAdminKeys: []string{
+ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMJlb/qf2B2kMNdBxfpCQqI2ctPcsOkdZGVh5zTRhKtH",
+ },
+ })
+ ac.AnonAccess = "read-only"
+ is.NoErr(err)
+ return testsession.New(tb, &ssh.Server{
+ Handler: bm.MiddlewareWithProgramHandler(SessionHandler(ac), termenv.ANSI256)(func(s ssh.Session) {
+ _, _, active := s.Pty()
+ tb.Logf("PTY active %v", active)
+ tb.Log(s.Command())
+ s.Exit(0)
+ }),
+ }, nil)
+}