package e2e import ( "encoding/json" "fmt" "io" "net" "net/http" "os" "path/filepath" "regexp" "strings" "sync/atomic" "testing" "time" ) // pagesGet fetches a path with a pages Host header against the instance. func (i *instance) pagesGet(t *testing.T, host, path string) (*http.Response, string) { t.Helper() req, err := http.NewRequest("GET", fmt.Sprintf("http://127.0.0.1:%d%s", i.httpPort, path), nil) if err != nil { t.Fatal(err) } req.Host = host resp, err := (&http.Client{CheckRedirect: func(*http.Request, []*http.Request) error { return http.ErrUseLastResponse }}).Do(req) if err != nil { t.Fatal(err) } defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) return resp, string(body) } // fakeDNS answers every TXT query with the string in txt (none when empty), // standing in for the challenge record during domain verification. func fakeDNS(t *testing.T, txt *atomic.Value) string { t.Helper() pc, err := net.ListenPacket("udp", "127.0.0.1:0") if err != nil { t.Fatal(err) } t.Cleanup(func() { pc.Close() }) go func() { buf := make([]byte, 512) for { n, addr, err := pc.ReadFrom(buf) if err != nil { return } q := buf[:n] if len(q) < 12 { continue } i := 12 for i < len(q) && q[i] != 0 { i += int(q[i]) + 1 } i += 5 // name terminator + qtype + qclass if i > len(q) { continue } val, _ := txt.Load().(string) resp := []byte{q[0], q[1], 0x81, 0x80, 0, 1, 0, 0, 0, 0, 0, 0} if val != "" { resp[7] = 1 } resp = append(resp, q[12:i]...) if val != "" { resp = append(resp, 0xC0, 0x0C, 0, 16, 0, 1, 0, 0, 0, 60) rdata := append([]byte{byte(len(val))}, val...) resp = append(resp, byte(len(rdata)>>8), byte(len(rdata))) resp = append(resp, rdata...) } pc.WriteTo(resp, addr) } }() return pc.LocalAddr().String() } func TestPages(t *testing.T) { var challenge atomic.Value challenge.Store("") t.Setenv("GITBAY_DNS_SERVER", fakeDNS(t, &challenge)) t.Setenv("GITBAY_DOMAIN_PENDING_TTL", "5s") inst := startInstanceWith(t, "[pages]\ndomain = \"p.test\"\n") aliceKey := inst.newKey(t, "alice") inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") env := inst.gitEnv(aliceKey) pushPages := func(repo string, files map[string]string) { t.Helper() if _, errOut, code := inst.ssh(t, aliceKey, "", "repo", "create", repo); code != 0 { t.Fatalf("create %s: %s", repo, errOut) } work := t.TempDir() mustGit(t, work, env, "clone", inst.sshURL(repo), "w") dir := filepath.Join(work, "w") for name, content := range files { os.MkdirAll(filepath.Dir(filepath.Join(dir, name)), 0o755) os.WriteFile(filepath.Join(dir, name), []byte(content), 0o644) } mustGit(t, dir, env, "checkout", "-q", "-b", "pages") mustGit(t, dir, env, "add", ".") mustGit(t, dir, env, "commit", "-q", "-m", "site") mustGit(t, dir, env, "push", "-q", "origin", "pages") } pushPages("alice/pages", map[string]string{ "index.html": "