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