server_test.go

  1package server
  2
  3import (
  4	"fmt"
  5	"net"
  6	"os"
  7	"path/filepath"
  8	"strconv"
  9	"strings"
 10	"testing"
 11
 12	"github.com/charmbracelet/keygen"
 13	"github.com/charmbracelet/soft-serve/server/config"
 14	"github.com/gliderlabs/ssh"
 15	"github.com/go-git/go-billy/v5/memfs"
 16	"github.com/go-git/go-git/v5"
 17	gconfig "github.com/go-git/go-git/v5/config"
 18	"github.com/go-git/go-git/v5/plumbing/object"
 19	gssh "github.com/go-git/go-git/v5/plumbing/transport/ssh"
 20	"github.com/go-git/go-git/v5/storage/memory"
 21	"github.com/matryer/is"
 22	gossh "golang.org/x/crypto/ssh"
 23)
 24
 25func TestPushRepo(t *testing.T) {
 26	is := is.New(t)
 27	s, cfg, pkPath := setupServer(t)
 28	err := s.Reload()
 29	is.NoErr(err)
 30	rp := t.TempDir()
 31	r, err := git.PlainInit(rp, false)
 32	is.NoErr(err)
 33	wt, err := r.Worktree()
 34	is.NoErr(err)
 35	_, err = wt.Filesystem.Create("testfile")
 36	is.NoErr(err)
 37	_, err = wt.Add("testfile")
 38	is.NoErr(err)
 39	author := &object.Signature{
 40		Name:  "test",
 41		Email: "",
 42	}
 43	_, err = wt.Commit("test commit", &git.CommitOptions{
 44		All:       true,
 45		Author:    author,
 46		Committer: author,
 47	})
 48	is.NoErr(err)
 49	_, err = r.CreateRemote(&gconfig.RemoteConfig{
 50		Name: "origin",
 51		URLs: []string{fmt.Sprintf("ssh://localhost:%d/%s", cfg.SSH.Port, "testrepo")},
 52	})
 53	auth, err := gssh.NewPublicKeysFromFile("git", pkPath, "")
 54	is.NoErr(err)
 55	auth.HostKeyCallbackHelper = gssh.HostKeyCallbackHelper{
 56		HostKeyCallback: gossh.InsecureIgnoreHostKey(),
 57	}
 58	t.Logf("pushing to ssh://localhost:%d/%s", cfg.SSH.Port, "testrepo")
 59	err = r.Push(&git.PushOptions{
 60		RemoteName: "origin",
 61		Auth:       auth,
 62	})
 63	is.NoErr(err)
 64}
 65
 66func TestCloneRepo(t *testing.T) {
 67	is := is.New(t)
 68	s, cfg, pkPath := setupServer(t)
 69	t.Log("starting server")
 70	err := s.Reload()
 71	t.Log("reloaded server")
 72	is.NoErr(err)
 73	dst := t.TempDir()
 74	t.Cleanup(func() { is.NoErr(os.RemoveAll(dst)) })
 75	url := fmt.Sprintf("ssh://localhost:%d/config", cfg.SSH.Port)
 76	t.Log("cloning repo")
 77	pk, err := gssh.NewPublicKeysFromFile("git", pkPath, "")
 78	is.NoErr(err)
 79	pk.HostKeyCallbackHelper = gssh.HostKeyCallbackHelper{
 80		HostKeyCallback: gossh.InsecureIgnoreHostKey(),
 81	}
 82	_, err = git.Clone(memory.NewStorage(), memfs.New(), &git.CloneOptions{
 83		URL:  url,
 84		Auth: pk,
 85	})
 86	is.NoErr(err)
 87}
 88
 89func randomPort() int {
 90	addr, _ := net.Listen("tcp", ":0") //nolint:gosec
 91	_ = addr.Close()
 92	return addr.Addr().(*net.TCPAddr).Port
 93}
 94
 95func setupServer(t *testing.T) (*Server, *config.Config, string) {
 96	t.Helper()
 97	is := is.New(t)
 98	pub, pkPath := createKeyPair(t)
 99	dp := t.TempDir()
100	is.NoErr(os.Setenv("SOFT_SERVE_DATA_PATH", dp))
101	is.NoErr(os.Setenv("SOFT_SERVE_INITIAL_ADMIN_KEY", authorizedKey(pub)))
102	is.NoErr(os.Setenv("SOFT_SERVE_GIT_ENABLED", "false"))
103	is.NoErr(os.Setenv("SOFT_SERVE_SSH_PORT", strconv.Itoa(randomPort())))
104	// is.NoErr(os.Setenv("SOFT_SERVE_DB_DRIVER", "fake"))
105	t.Cleanup(func() {
106		is.NoErr(os.Unsetenv("SOFT_SERVE_DATA_PATH"))
107		is.NoErr(os.Unsetenv("SOFT_SERVE_SSH_PORT"))
108		is.NoErr(os.Unsetenv("SOFT_SERVE_INITIAL_ADMIN_KEY"))
109		is.NoErr(os.Unsetenv("SOFT_SERVE_GIT_ENABLED"))
110		// is.NoErr(os.Unsetenv("SOFT_SERVE_DB_DRIVER"))
111		is.NoErr(os.RemoveAll(dp))
112	})
113	cfg := config.DefaultConfig() //.WithDB(&fakedb.FakeDB{})
114	s := NewServer(cfg)
115	go func() {
116		t.Log("starting server")
117		s.Start()
118	}()
119	t.Cleanup(func() {
120		s.Close()
121	})
122	return s, cfg, pkPath
123}
124
125func createKeyPair(t *testing.T) (ssh.PublicKey, string) {
126	t.Helper()
127	is := is.New(t)
128	keyDir := t.TempDir()
129	kp, err := keygen.NewWithWrite(filepath.Join(keyDir, "id"), nil, keygen.Ed25519)
130	is.NoErr(err)
131	pubkey, _, _, _, err := ssh.ParseAuthorizedKey(kp.PublicKey())
132	is.NoErr(err)
133	return pubkey, filepath.Join(keyDir, "id_ed25519")
134}
135
136func authorizedKey(pk ssh.PublicKey) string {
137	return strings.TrimSpace(string(gossh.MarshalAuthorizedKey(pk)))
138}