package e2e
import (
"compress/gzip"
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"strings"
"testing"
"golang.org/x/crypto/ssh"
"gitbay.org/gitbay/internal/sig"
)
func (i *instance) get(t *testing.T, path string) (int, string) {
t.Helper()
resp, err := http.Get(fmt.Sprintf("http://127.0.0.1:%d%s", i.httpPort, path))
if err != nil {
t.Fatal(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
return resp.StatusCode, string(body)
}
func TestWebUI(t *testing.T) {
inst := startInstance(t)
aliceKey := inst.newKey(t, "alice")
inst.admin(t, "admin", "user", "create", "alice",
"--key", aliceKey+".pub", "--email", "alice@example.test", "--verified")
// Public repo with real content: a README, a source file, a tag, and
// one SSHSIG-signed commit for the badge check.
if _, errOut, code := inst.ssh(t, aliceKey, "", "repo", "create", "alice/site"); code != 0 {
t.Fatalf("repo create: %s", errOut)
}
work := t.TempDir()
env := inst.gitEnv(aliceKey)
mustGit(t, work, env, "clone", inst.sshURL("alice/site"), "w")
dir := filepath.Join(work, "w")
os.WriteFile(filepath.Join(dir, "README.md"), []byte("# hello site\n\nsome *markdown*\n"), 0o644)
os.MkdirAll(filepath.Join(dir, "src"), 0o755)
os.WriteFile(filepath.Join(dir, "src", "main.go"), []byte("package main\n\nfunc main() {}\n"), 0o644)
mustGit(t, dir, env, "checkout", "-q", "-b", "main")
mustGit(t, dir, env, "add", ".")
mustGit(t, dir, env, "commit", "-q", "-m", "first commit")
mustGit(t, dir, env, "tag", "v1.0")
mustGit(t, dir, env, "push", "-q", "origin", "main", "v1.0")
// A signed commit on top, built with the M4 fixture helpers.
sshRaw, _ := os.ReadFile(aliceKey)
signer, err := ssh.ParsePrivateKey(sshRaw)
if err != nil {
t.Fatal(err)
}
head := strings.TrimSpace(mustGit(t, dir, env, "rev-parse", "HEAD"))
buildSignedCommitOn(t, dir, env, head, "signed tip", "alice@example.test", signer)
mustGit(t, dir, env, "push", "-q", "origin", "main")
// Private repo must be invisible everywhere.
if _, _, code := inst.ssh(t, aliceKey, "", "repo", "create", "alice/secret", "--private"); code != 0 {
t.Fatal("create private failed")
}
// Explore lists the public repo, not the private one; the anonymous
// homepage is a landing page pointing there.
status, body := inst.get(t, "/")
if status != 200 || !strings.Contains(body, `href="/explore"`) {
t.Fatalf("landing: %d\n%s", status, body)
}
status, body = inst.get(t, "/explore")
if status != 200 || !strings.Contains(body, "alice/site") {
t.Fatalf("explore: %d\n%s", status, body)
}
if strings.Contains(body, "secret") {
t.Fatal("explore leaks private repo")
}
// Repo home: tree entries plus rendered README.
status, body = inst.get(t, "/alice/site")
if status != 200 || !strings.Contains(body, "src/") || !strings.Contains(body, "README.md") {
t.Fatalf("repo home: %d\n%s", status, body)
}
// Both clone URLs: SSH for anyone with a key, HTTPS for reading.
if !strings.Contains(body, "git clone ssh://git@gitbay.test:") || !strings.Contains(body, "/alice/site.git ยท git clone https://gitbay.test/alice/site.git") {
t.Fatalf("clone URLs missing:\n%s", body)
}
if !strings.Contains(body, "
fine
") status, body = inst.get(t, "/alice/htmldoc") if status != 200 || !strings.Contains(body, "fine") { t.Fatalf("html README not rendered:\n%s", body) } if strings.Contains(body, "