Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/git/vole.git

Write over SSH with a registered key:

git clone ssh://git@0.0.0.0:2222/vole.git

A free and open-source forge that lives in your Git repo.

Blame · server/goimport_test.go

Line attribution on main · 82 line(s)

d37d301f
Keenan Nemetz
16h ago
1 package server_test
2
3 // A repository is a Go module without a vanity service: the go command's
4 // discovery probe at <host>/<repository> gets a go-import tag naming the Git
5 // transport, and nothing in front of the forge has to serve it.
6
7 import (
8 "fmt"
9 "net/http"
10 "strings"
11 "testing"
12
13 "rodent.software/vole/forge/config"
14 )
15
16 func TestPublicRepositoryServesGoImportMetadata(t *testing.T) {
17 t.Parallel()
18 const site = "https://forge.example.com"
19 f := newFixtureWith(t, func(c *config.Config) { c.PublicURL = site })
20 f.publish(f.repo)
21
ed03b3d1
Keenan Nemetz
3h ago
22 tag := fmt.Sprintf(`<meta name="go-import" content="forge.example.com/%s git %s/%s.git">`, f.repo, site, f.repo)
d37d301f
Keenan Nemetz
16h ago
23 for _, path := range []string{
24 "/" + f.repo + "?go-get=1",
25 // A package inside the module asks at its own path first; the same tag
26 // answers for the whole prefix, which is what makes one lookup enough.
27 "/" + f.repo + "/server/web?go-get=1",
28 "/" + f.repo + "/?go-get=1",
29 } {
30 code, body := f.get(path)
31 if code != http.StatusOK {
32 t.Fatalf("%s = %d, want 200", path, code)
33 }
34 if !strings.Contains(body, tag) {
35 t.Fatalf("%s does not carry the go-import tag:\n%s", path, body)
36 }
37 }
38
39 // The tag is HTML the go command parses, and nothing else is.
40 resp, err := http.Get(f.http.URL + "/" + f.repo + "?go-get=1")
41 if err != nil {
42 t.Fatal(err)
43 }
44 resp.Body.Close()
45 if ct := resp.Header.Get("Content-Type"); !strings.HasPrefix(ct, "text/html") {
46 t.Fatalf("content type = %q, want HTML", ct)
47 }
48
ed03b3d1
Keenan Nemetz
3h ago
49 // Without the probe the path is the repository page: the module path and the
50 // page a person opens are the same URL.
51 for _, path := range []string{"/" + f.repo, "/" + f.repo + "?go-get=0"} {
52 if code, _ := f.get(path); code != http.StatusOK {
53 t.Fatalf("%s = %d, want the repository page", path, code)
54 }
d37d301f
Keenan Nemetz
16h ago
55 }
56 }
57
58 // The tag is fetched without credentials, so answering for a private repository
59 // would confirm its existence to anyone who guessed the name.
60 func TestPrivateRepositoryDoesNotAdvertiseAGoModule(t *testing.T) {
61 t.Parallel()
62 f := newFixture(t)
63 if code, _ := f.get("/" + f.repo + "?go-get=1"); code != http.StatusNotFound {
64 t.Fatalf("private repository answered the discovery probe: %d", code)
65 }
66 }
67
68 // Nothing names a repository, so nothing is answered. An unknown name is a 404
69 // like every other unknown path.
70 func TestGoImportIgnoresPathsThatNameNoRepository(t *testing.T) {
71 t.Parallel()
72 f := newFixture(t)
73 f.publish(f.repo)
74 for _, path := range []string{
75 "/no-such-repository?go-get=1",
76 "/no-such-repository/pkg?go-get=1",
77 } {
78 if code, _ := f.get(path); code != http.StatusNotFound {
79 t.Fatalf("%s = %d, want 404", path, code)
80 }
81 }
82 }