Parent directory

repo_test.go

2826 bytes
 1package backend
 2
 3import (
 4	"context"
 5	"errors"
 6	"slices"
 7	"testing"
 8
 9	"github.com/charmbracelet/soft-serve/pkg/db"
10	"github.com/charmbracelet/soft-serve/pkg/proto"
11	"github.com/matryer/is"
12)
13
14// TestCreateRepositoryAnonymousOwner verifies that a repository created with
15// a nil user (an anon-access/allow-keyless override) is owned by the
16// lowest-ID admin rather than failing the NOT NULL repos.user_id constraint.
17func TestCreateRepositoryAnonymousOwner(t *testing.T) {
18	is := is.New(t)
19	be, _ := newTestBackend(t)
20	ctx := context.Background()
21
22	admin, err := be.User(ctx, "admin")
23	is.NoErr(err)
24
25	repo, err := be.CreateRepository(ctx, "anon-repo", nil, proto.RepositoryOptions{})
26	is.NoErr(err)
27	is.Equal(repo.UserID(), admin.ID())
28}
29
30// TestDefaultAdminUserIDNoAdmin verifies that defaultAdminUserID surfaces an
31// error rather than silently returning a zero user ID (which would violate
32// the NOT NULL repos.user_id constraint) when the database has no admin.
33func TestDefaultAdminUserIDNoAdmin(t *testing.T) {
34	is := is.New(t)
35	be, _ := newTestBackend(t)
36	ctx := context.Background()
37
38	err := be.db.TransactionContext(ctx, func(tx *db.Tx) error {
39		if _, err := tx.ExecContext(ctx, "UPDATE users SET admin = false"); err != nil {
40			return err
41		}
42
43		_, err := be.defaultAdminUserID(ctx, tx)
44		return err
45	})
46	is.True(err != nil)
47}
48
49// TestValidateImportRemote verifies that import remotes pointing at private,
50// internal, or non-network destinations are rejected, and that accepted
51// remotes carry the git environment that keeps the validation honest.
52func TestValidateImportRemote(t *testing.T) {
53	tests := []struct {
54		name    string
55		remote  string
56		wantErr bool
57	}{
58		{"public https", "https://1.1.1.1/x.git", false},
59		{"public git", "git://1.1.1.1/x.git", false},
60		{"ssh", "ssh://git@10.0.0.1/x.git", false},
61
62		{"loopback", "http://127.0.0.1/x.git", true},
63		{"localhost", "http://localhost:8080/x.git", true},
64		{"private network", "http://10.0.0.1/x.git", true},
65		{"cloud metadata", "http://169.254.169.254/latest/meta-data/", true},
66		{"git scheme private", "git://10.0.0.1/x.git", true},
67		{"octal loopback", "http://0177.0.0.1/x.git", true},
68		{"local path", "/data/repos/secret.git", true},
69		{"file scheme", "file:///etc/passwd", true},
70		{"empty", "", true},
71	}
72
73	for _, tt := range tests {
74		t.Run(tt.name, func(t *testing.T) {
75			is := is.New(t)
76			env, err := validateImportRemote(tt.remote)
77
78			if tt.wantErr {
79				is.True(err != nil)
80				is.True(errors.Is(err, proto.ErrInvalidRemote))
81				return
82			}
83
84			is.NoErr(err)
85			// Redirect following must be off, or a public remote can hand
86			// off to an internal one after validation has passed.
87			is.True(slices.Contains(env, "GIT_CONFIG_VALUE_0=false"))
88			is.True(slices.Contains(env, "GIT_CONFIG_KEY_0=http.followRedirects"))
89		})
90	}
91}