internal/gitpin/gitpin_test.go
110 lines · 4121 bytes
6 symbols in this file
1package gitpin
2
3import (
4 "context"
5 "net"
6 "net/url"
7 "slices"
8 "strings"
9 "testing"
10)
11
12func answer(ips ...string) Lookup {
13 return func(context.Context, string) ([]net.IP, error) {
14 var out []net.IP
15 for _, s := range ips {
16 out = append(out, net.ParseIP(s))
17 }
18 return out, nil
19 }
20}
21
22func TestResolve(t *testing.T) {
23 ctx := context.Background()
24 r, err := Resolve(ctx, answer("203.0.113.5"), "https://git.example/x.git", false)
25 if err != nil || r.URL.Hostname() != "git.example" || len(r.IPs) != 1 {
26 t.Fatalf("public: %+v %v", r, err)
27 }
28 if _, err := Resolve(ctx, answer("203.0.113.5", "10.0.0.7"), "https://git.example/x.git", false); err == nil || !strings.Contains(err.Error(), "10.0.0.7") {
29 t.Fatalf("private: %v", err)
30 }
31 if _, err := Resolve(ctx, answer("10.0.0.7"), "https://git.example/x.git", true); err != nil {
32 t.Fatalf("allow_local: %v", err)
33 }
34 // An empty resolve list would leave curl to resolve the host itself.
35 if _, err := Resolve(ctx, answer(), "https://git.example/x.git", true); err == nil || !strings.Contains(err.Error(), "no address") {
36 t.Fatalf("empty answer: %v", err)
37 }
38 for _, raw := range []string{"git://git.example/x.git", "ssh://git.example/x.git", "file:///etc"} {
39 _, err := Resolve(ctx, func(context.Context, string) ([]net.IP, error) {
40 t.Fatalf("looked up a host for %s", raw)
41 return nil, nil
42 }, raw, true)
43 if err == nil || !strings.Contains(err.Error(), "not http or https") {
44 t.Errorf("%s: %v", raw, err)
45 }
46 }
47}
48
49// Numeric hosts other than a dotted quad are refused before any lookup:
50// curl reads them as addresses the check never saw.
51func TestResolveRefusesOddNumericHosts(t *testing.T) {
52 never := func(_ context.Context, host string) ([]net.IP, error) {
53 t.Fatalf("looked up %s", host)
54 return nil, nil
55 }
56 for _, host := range []string{"127.1", "2130706433", "0x7f.1", "0x7F000001", "017700000001", "127.0.0.01", "127.0.0.1."} {
57 if _, err := Resolve(context.Background(), never, "http://"+host+"/x.git", true); err == nil || !strings.Contains(err.Error(), "numeric address") {
58 t.Errorf("%s: %v", host, err)
59 }
60 }
61 // Names with a numeric label, and real literals, still pass.
62 for _, host := range []string{"1.example", "0x7f.example", "203.0.113.5", "[2001:db8::1]"} {
63 if _, err := Resolve(context.Background(), answer("203.0.113.5"), "http://"+host+"/x.git", false); err != nil {
64 t.Errorf("%s: %v", host, err)
65 }
66 }
67}
68
69func TestArgs(t *testing.T) {
70 u, _ := url.Parse("https://git.example/x.git")
71 got := Remote{u, []net.IP{net.ParseIP("203.0.113.5"), net.ParseIP("2001:db8::1")}}.Args()
72 want := []string{"-c", "http.followRedirects=false",
73 "-c", "http.curloptResolve=git.example:443:203.0.113.5,[2001:db8::1]",
74 "-c", "http.curloptResolve=*:443:203.0.113.5,[2001:db8::1]"}
75 if !slices.Equal(got, want) {
76 t.Fatalf("https: %q", got)
77 }
78 u, _ = url.Parse("http://git.example:8080/x.git")
79 if got := (Remote{u, []net.IP{net.ParseIP("203.0.113.5")}}).Args(); got[3] != "http.curloptResolve=git.example:8080:203.0.113.5" ||
80 got[5] != "http.curloptResolve=*:8080:203.0.113.5" {
81 t.Fatalf("http with port: %q", got)
82 }
83 // An address literal is its own resolution; there is nothing to pin.
84 u, _ = url.Parse("https://203.0.113.5/x.git")
85 if got := (Remote{u, []net.IP{net.ParseIP("203.0.113.5")}}).Args(); !slices.Equal(got, []string{"-c", "http.followRedirects=false"}) {
86 t.Fatalf("literal: %q", got)
87 }
88}
89
90func TestEnv(t *testing.T) {
91 want := []string{"GIT_TERMINAL_PROMPT=0", "HOME=/srv/gitbay",
92 "GIT_CONFIG_NOSYSTEM=1", "GIT_CONFIG_GLOBAL=/dev/null"}
93 if got := Env("/srv/gitbay"); !slices.Equal(got, want) {
94 t.Fatalf("Env = %q", got)
95 }
96}
97
98func TestVersionOK(t *testing.T) {
99 for _, s := range []string{"git version 2.37.0", "git version 2.47.3", "git version 2.39.5 (Apple Git-154)",
100 "git version 2.45.2.windows.1", "git version 3.0.0\n"} {
101 if err := VersionOK(s); err != nil {
102 t.Errorf("%q: %v", s, err)
103 }
104 }
105 for _, s := range []string{"git version 2.36.9", "git version 1.99.0", "git version 2", "nonsense", ""} {
106 if err := VersionOK(s); err == nil {
107 t.Errorf("%q accepted", s)
108 }
109 }
110}