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}