Skip to content

Commit 7d0b285

Browse files
aryan9600Paulo Gomes
andcommitted
expand proxy tests to cover managed transport
Signed-off-by: Sanskar Jaiswal <[email protected]> Co-authored-by: Paulo Gomes <[email protected]>
1 parent 8849078 commit 7d0b285

File tree

1 file changed

+122
-52
lines changed

1 file changed

+122
-52
lines changed

pkg/git/strategy/proxy/strategy_proxy_test.go

Lines changed: 122 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,23 @@ import (
2929

3030
"github.com/elazarl/goproxy"
3131
"github.com/fluxcd/pkg/gittestserver"
32+
"github.com/go-logr/logr"
3233
. "github.com/onsi/gomega"
3334

3435
"github.com/fluxcd/source-controller/pkg/git"
3536
"github.com/fluxcd/source-controller/pkg/git/gogit"
3637
"github.com/fluxcd/source-controller/pkg/git/libgit2"
38+
"github.com/fluxcd/source-controller/pkg/git/libgit2/managed"
3739
"github.com/fluxcd/source-controller/pkg/git/strategy"
3840
)
3941

4042
// These tests are run in a different _test.go file because go-git uses the ProxyFromEnvironment function of the net/http package
4143
// which caches the Proxy settings, hence not including other tests in the same file ensures a clean proxy setup for the tests to run.
4244
func TestCheckoutStrategyForImplementation_Proxied(t *testing.T) {
45+
// for libgit2 we are only testing for managed transport,
46+
// as unmanaged is sunsetting.
47+
// Unmanaged transport does not support HTTP_PROXY.
48+
managed.InitManagedTransport(logr.Discard())
4349

4450
type cleanupFunc func()
4551

@@ -62,8 +68,104 @@ func TestCheckoutStrategyForImplementation_Proxied(t *testing.T) {
6268
proxyAddr := fmt.Sprintf("localhost:%d", l.Addr().(*net.TCPAddr).Port)
6369
g.Expect(l.Close()).ToNot(HaveOccurred())
6470

65-
// Note there is no libgit2 HTTP_PROXY test as libgit2 doesnt support proxied HTTP requests.
6671
cases := []testCase{
72+
{
73+
name: "gogit_HTTP_PROXY",
74+
gitImpl: gogit.Implementation,
75+
url: "http://example.com/bar/test-reponame",
76+
branch: "main",
77+
setupGitProxy: func(g *WithT, proxy *goproxy.ProxyHttpServer, proxyGotRequest *bool) (*git.AuthOptions, cleanupFunc) {
78+
// Create the git server.
79+
gitServer, err := gittestserver.NewTempGitServer()
80+
g.Expect(err).ToNot(HaveOccurred())
81+
82+
username := "test-user"
83+
password := "test-password"
84+
gitServer.Auth(username, password)
85+
gitServer.KeyDir(gitServer.Root())
86+
87+
g.Expect(gitServer.StartHTTP()).ToNot(HaveOccurred())
88+
89+
// Initialize a git repo.
90+
err = gitServer.InitRepo("../testdata/repo1", "main", "bar/test-reponame")
91+
g.Expect(err).ToNot(HaveOccurred())
92+
93+
u, err := url.Parse(gitServer.HTTPAddress())
94+
g.Expect(err).ToNot(HaveOccurred())
95+
96+
// The request is being forwarded to the local test git server in this handler.
97+
var proxyHandler goproxy.FuncReqHandler = func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
98+
userAgent := req.Header.Get("User-Agent")
99+
if strings.Contains(req.Host, "example.com") && strings.Contains(userAgent, "git") {
100+
*proxyGotRequest = true
101+
req.Host = u.Host
102+
req.URL.Host = req.Host
103+
return req, nil
104+
}
105+
// Reject if it isnt our request.
106+
return req, goproxy.NewResponse(req, goproxy.ContentTypeText, http.StatusForbidden, "")
107+
}
108+
proxy.OnRequest().Do(proxyHandler)
109+
110+
return &git.AuthOptions{
111+
Transport: git.HTTP,
112+
Username: username,
113+
Password: password,
114+
}, func() {
115+
os.RemoveAll(gitServer.Root())
116+
gitServer.StopHTTP()
117+
}
118+
},
119+
shortTimeout: false,
120+
wantUsedProxy: true,
121+
wantError: false,
122+
},
123+
{
124+
name: "gogit_HTTPS_PROXY",
125+
gitImpl: gogit.Implementation,
126+
url: "https://github.com/git-fixtures/basic",
127+
branch: "master",
128+
setupGitProxy: func(g *WithT, proxy *goproxy.ProxyHttpServer, proxyGotRequest *bool) (*git.AuthOptions, cleanupFunc) {
129+
var proxyHandler goproxy.FuncHttpsHandler = func(host string, ctx *goproxy.ProxyCtx) (*goproxy.ConnectAction, string) {
130+
// We don't check for user agent as this handler is only going to process CONNECT requests, and because Go's net/http
131+
// is the one making such a request on behalf of go-git, adding a check for the go net/http user agent (Go-http-client)
132+
// would only allow false positives from any request originating from Go's net/http.
133+
if strings.Contains(host, "github.com") {
134+
*proxyGotRequest = true
135+
return goproxy.OkConnect, host
136+
}
137+
// Reject if it isnt our request.
138+
return goproxy.RejectConnect, host
139+
}
140+
proxy.OnRequest().HandleConnect(proxyHandler)
141+
142+
// go-git does not allow to use an HTTPS proxy and a custom root CA at the same time.
143+
// See https://github.com/fluxcd/source-controller/pull/524#issuecomment-1006673163.
144+
return nil, func() {}
145+
},
146+
shortTimeout: false,
147+
wantUsedProxy: true,
148+
wantError: false,
149+
},
150+
{
151+
name: "gogit_NO_PROXY",
152+
gitImpl: gogit.Implementation,
153+
url: "https://192.0.2.1/bar/test-reponame",
154+
branch: "main",
155+
setupGitProxy: func(g *WithT, proxy *goproxy.ProxyHttpServer, proxyGotRequest *bool) (*git.AuthOptions, cleanupFunc) {
156+
var proxyHandler goproxy.FuncHttpsHandler = func(host string, ctx *goproxy.ProxyCtx) (*goproxy.ConnectAction, string) {
157+
// We shouldn't hit the proxy so we just want to check for any interaction, then reject.
158+
*proxyGotRequest = true
159+
return goproxy.RejectConnect, host
160+
}
161+
proxy.OnRequest().HandleConnect(proxyHandler)
162+
163+
return nil, func() {}
164+
},
165+
shortTimeout: true,
166+
wantUsedProxy: false,
167+
wantError: true,
168+
},
67169
{
68170
name: "libgit2_HTTPS_PROXY",
69171
gitImpl: libgit2.Implementation,
@@ -100,6 +202,7 @@ func TestCheckoutStrategyForImplementation_Proxied(t *testing.T) {
100202
// The request is being forwarded to the local test git server in this handler.
101203
// The certificate used here is valid for both example.com and localhost.
102204
var proxyHandler goproxy.FuncHttpsHandler = func(host string, ctx *goproxy.ProxyCtx) (*goproxy.ConnectAction, string) {
205+
defer managed.RemoveTransportOptions("https://example.com/bar/test-reponame")
103206
// Check if the host matches with the git server address and the user-agent is the expected git client.
104207
userAgent := ctx.Req.Header.Get("User-Agent")
105208
if strings.Contains(host, "example.com") && strings.Contains(userAgent, "libgit2") {
@@ -112,10 +215,11 @@ func TestCheckoutStrategyForImplementation_Proxied(t *testing.T) {
112215
proxy.OnRequest().HandleConnect(proxyHandler)
113216

114217
return &git.AuthOptions{
115-
Transport: git.HTTPS,
116-
Username: username,
117-
Password: password,
118-
CAFile: exampleCA,
218+
Transport: git.HTTPS,
219+
Username: username,
220+
Password: password,
221+
CAFile: exampleCA,
222+
TransportOptionsURL: "https://proxy-test",
119223
}, func() {
120224
os.RemoveAll(gitServer.Root())
121225
gitServer.StopHTTP()
@@ -126,33 +230,31 @@ func TestCheckoutStrategyForImplementation_Proxied(t *testing.T) {
126230
wantError: false,
127231
},
128232
{
129-
name: "gogit_HTTP_PROXY",
130-
gitImpl: gogit.Implementation,
233+
name: "libgit2_HTTP_PROXY",
234+
gitImpl: libgit2.Implementation,
131235
url: "http://example.com/bar/test-reponame",
132236
branch: "main",
133237
setupGitProxy: func(g *WithT, proxy *goproxy.ProxyHttpServer, proxyGotRequest *bool) (*git.AuthOptions, cleanupFunc) {
134238
// Create the git server.
135239
gitServer, err := gittestserver.NewTempGitServer()
136240
g.Expect(err).ToNot(HaveOccurred())
137241

138-
username := "test-user"
139-
password := "test-password"
140-
gitServer.Auth(username, password)
141-
gitServer.KeyDir(gitServer.Root())
142-
143-
g.Expect(gitServer.StartHTTP()).ToNot(HaveOccurred())
242+
err = gitServer.StartHTTP()
243+
g.Expect(err).ToNot(HaveOccurred())
144244

145245
// Initialize a git repo.
146-
err = gitServer.InitRepo("../testdata/repo1", "main", "bar/test-reponame")
246+
repoPath := "bar/test-reponame"
247+
err = gitServer.InitRepo("../testdata/repo1", "main", repoPath)
147248
g.Expect(err).ToNot(HaveOccurred())
148249

149250
u, err := url.Parse(gitServer.HTTPAddress())
150251
g.Expect(err).ToNot(HaveOccurred())
151252

152253
// The request is being forwarded to the local test git server in this handler.
254+
// The certificate used here is valid for both example.com and localhost.
153255
var proxyHandler goproxy.FuncReqHandler = func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
154256
userAgent := req.Header.Get("User-Agent")
155-
if strings.Contains(req.Host, "example.com") && strings.Contains(userAgent, "git") {
257+
if strings.Contains(req.Host, "example.com") && strings.Contains(userAgent, "libgit2") {
156258
*proxyGotRequest = true
157259
req.Host = u.Host
158260
req.URL.Host = req.Host
@@ -164,9 +266,8 @@ func TestCheckoutStrategyForImplementation_Proxied(t *testing.T) {
164266
proxy.OnRequest().Do(proxyHandler)
165267

166268
return &git.AuthOptions{
167-
Transport: git.HTTP,
168-
Username: username,
169-
Password: password,
269+
Transport: git.HTTP,
270+
TransportOptionsURL: "http://proxy-test",
170271
}, func() {
171272
os.RemoveAll(gitServer.Root())
172273
gitServer.StopHTTP()
@@ -177,35 +278,8 @@ func TestCheckoutStrategyForImplementation_Proxied(t *testing.T) {
177278
wantError: false,
178279
},
179280
{
180-
name: "gogit_HTTPS_PROXY",
181-
gitImpl: gogit.Implementation,
182-
url: "https://github.com/git-fixtures/basic",
183-
branch: "master",
184-
setupGitProxy: func(g *WithT, proxy *goproxy.ProxyHttpServer, proxyGotRequest *bool) (*git.AuthOptions, cleanupFunc) {
185-
var proxyHandler goproxy.FuncHttpsHandler = func(host string, ctx *goproxy.ProxyCtx) (*goproxy.ConnectAction, string) {
186-
// We don't check for user agent as this handler is only going to process CONNECT requests, and because Go's net/http
187-
// is the one making such a request on behalf of go-git, adding a check for the go net/http user agent (Go-http-client)
188-
// would only allow false positives from any request originating from Go's net/http.
189-
if strings.Contains(host, "github.com") {
190-
*proxyGotRequest = true
191-
return goproxy.OkConnect, host
192-
}
193-
// Reject if it isnt our request.
194-
return goproxy.RejectConnect, host
195-
}
196-
proxy.OnRequest().HandleConnect(proxyHandler)
197-
198-
// go-git does not allow to use an HTTPS proxy and a custom root CA at the same time.
199-
// See https://github.com/fluxcd/source-controller/pull/524#issuecomment-1006673163.
200-
return nil, func() {}
201-
},
202-
shortTimeout: false,
203-
wantUsedProxy: true,
204-
wantError: false,
205-
},
206-
{
207-
name: "gogit_NO_PROXY",
208-
gitImpl: gogit.Implementation,
281+
name: "libgit2_NO_PROXY",
282+
gitImpl: libgit2.Implementation,
209283
url: "https://192.0.2.1/bar/test-reponame",
210284
branch: "main",
211285
setupGitProxy: func(g *WithT, proxy *goproxy.ProxyHttpServer, proxyGotRequest *bool) (*git.AuthOptions, cleanupFunc) {
@@ -218,13 +292,10 @@ func TestCheckoutStrategyForImplementation_Proxied(t *testing.T) {
218292

219293
return nil, func() {}
220294
},
221-
shortTimeout: true,
295+
shortTimeout: false,
222296
wantUsedProxy: false,
223297
wantError: true,
224298
},
225-
// TODO: Add a NO_PROXY test for libgit2 once the version of libgit2 used by the source controller is updated to a version that includes
226-
// the NO_PROXY functionality
227-
// This PR introduces the functionality in libgit2: https://github.com/libgit2/libgit2/pull/6026
228299
}
229300

230301
for _, tt := range cases {
@@ -282,7 +353,6 @@ func TestCheckoutStrategyForImplementation_Proxied(t *testing.T) {
282353
}
283354

284355
g.Expect(proxyGotRequest).To(Equal(tt.wantUsedProxy))
285-
286356
})
287357
}
288358
}

0 commit comments

Comments
 (0)