Unverified Commit c7b94fe5 authored by Oren Shomron's avatar Oren Shomron Committed by GitHub
Browse files

Merge pull request #831 from shomron/issue-726-tls-skip-verify

Add --tls-skip-verify global option affecting outgoing HTTP requests
parents 746561a9 de033c2c
......@@ -17,6 +17,7 @@ package registry
import (
"fmt"
"net/http"
"strings"
"github.com/ksonnet/ksonnet/pkg/app"
......@@ -62,7 +63,8 @@ type registryConfigLister interface {
// packageManager is an implementation of PackageManager.
type packageManager struct {
app app.App
app app.App
httpClient *http.Client
InstallChecker pkg.InstallChecker
packagesFn func() ([]pkg.Package, error)
......@@ -73,15 +75,29 @@ type packageManager struct {
var _ PackageManager = (*packageManager)(nil)
// PackageManagerOpt configures a package mangager
type PackageManagerOpt func(*packageManager)
// HTTPClientOpt configures a packageManager with an http.Client
func HTTPClientOpt(httpClient *http.Client) PackageManagerOpt {
return func(pm *packageManager) {
pm.httpClient = httpClient
}
}
// NewPackageManager creates an instance of PackageManager.
func NewPackageManager(a app.App) PackageManager {
func NewPackageManager(a app.App, opts ...PackageManagerOpt) PackageManager {
pm := packageManager{
app: a,
InstallChecker: &pkg.DefaultInstallChecker{App: a},
}
// Allow httpClient and other options to be set
for _, optFn := range opts {
optFn(&pm)
}
pm.packagesFn = pm.Packages
pm.registriesFn = func() (map[string]SpecFetcher, error) {
r, err := resolveRegistries(a)
r, err := resolveRegistries(a, pm.httpClient)
if err != nil {
return nil, err
}
......@@ -89,7 +105,7 @@ func NewPackageManager(a app.App) PackageManager {
return registriesToSpecFetchers(r), nil
}
pm.resolverFn = func(name string) (LibrarySpecResolver, error) {
r, err := resolveRegistry(a, name)
r, err := resolveRegistry(a, name, pm.httpClient)
if err != nil {
return nil, err
}
......@@ -102,12 +118,13 @@ func NewPackageManager(a app.App) PackageManager {
return nil, errors.New("not implemented")
}
}
return &pm
}
// resolveRegistries returns a list of registries from the provided app.
// (SpecFetcher is a subset of the Registry interface)
func resolveRegistries(a app.App) (map[string]Registry, error) {
func resolveRegistries(a app.App, httpClient *http.Client) (map[string]Registry, error) {
if a == nil {
return nil, errors.New("nil app")
}
......@@ -119,7 +136,7 @@ func resolveRegistries(a app.App) (map[string]Registry, error) {
result := make(map[string]Registry)
for _, cfg := range cfgs {
r, err := Locate(a, cfg)
r, err := Locate(a, cfg, httpClient)
if err != nil {
return nil, errors.Wrapf(err, "resolving registry: %v", cfg.Name)
}
......@@ -130,12 +147,12 @@ func resolveRegistries(a app.App) (map[string]Registry, error) {
}
// resolveRegistry returns the named registry from the provided app.
func resolveRegistry(a app.App, name string) (Registry, error) {
func resolveRegistry(a app.App, name string, httpClient *http.Client) (Registry, error) {
if a == nil {
return nil, errors.New("nil app")
}
all, err := resolveRegistries(a)
all, err := resolveRegistries(a, httpClient)
if err != nil {
return nil, err
}
......
......@@ -77,12 +77,23 @@ func defaultHTTPClient() *http.Client {
}
type defaultGitHub struct {
httpClient httpClient
httpClient *http.Client
urlParse func(string) (*url.URL, error)
}
var _ GitHub = (*defaultGitHub)(nil)
// NewGitHub constructs a GitHub client
func NewGitHub(httpClient *http.Client) GitHub {
if httpClient == nil {
httpClient = defaultHTTPClient()
}
return &defaultGitHub{
httpClient: httpClient,
urlParse: url.Parse,
}
}
func (dg *defaultGitHub) ValidateURL(urlStr string) error {
u, err := dg.urlParse(urlStr)
if err != nil {
......@@ -130,16 +141,17 @@ func (dg *defaultGitHub) Contents(ctx context.Context, repo Repo, path, ref stri
}
func (dg *defaultGitHub) client() *github.Client {
var hc *http.Client
var httpClient = dg.httpClient
ght := os.Getenv("GITHUB_TOKEN")
if len(ght) > 0 {
ctx := context.Background()
// TODO WithTimeout
ctx := context.WithValue(context.Background(), oauth2.HTTPClient, dg.httpClient)
ts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: ght},
)
hc = oauth2.NewClient(ctx, ts)
httpClient = oauth2.NewClient(ctx, ts)
}
return github.NewClient(hc)
return github.NewClient(httpClient)
}
......@@ -16,57 +16,78 @@
package github
import (
"context"
"errors"
"net/http"
"net/url"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type fakeTransport struct {
resp *http.Response
err error
}
func (f *fakeTransport) RoundTrip(req *http.Request) (*http.Response, error) {
return f.resp, f.err
}
func fakeHTTPClient(resp *http.Response, err error) *http.Client {
c := &http.Client{
Transport: &fakeTransport{
resp: resp,
err: err,
},
}
return c
}
func Test_defaultGitHub_ValidateURL(t *testing.T) {
cases := []struct {
name string
url string
c httpClient
c *http.Client
urlParse func(string) (*url.URL, error)
isErr bool
}{
{
name: "url exists",
url: "https://github.com/ksonnet/parts",
c: &fakeHTTPClient{
headResp: &http.Response{
c: fakeHTTPClient(
&http.Response{
Status: http.StatusText(http.StatusOK),
StatusCode: http.StatusOK,
},
},
}, nil,
),
},
{
name: "hostname and path",
url: "github.com/ksonnet/parts",
c: &fakeHTTPClient{
headResp: &http.Response{
c: fakeHTTPClient(
&http.Response{
Status: http.StatusText(http.StatusOK),
StatusCode: http.StatusOK,
},
},
}, nil,
),
},
{
name: "client failure",
c: &fakeHTTPClient{
headErr: errors.New("failed"),
},
c: fakeHTTPClient(
nil, errors.New("failed"),
),
isErr: true,
},
{
name: "invalid status code",
c: &fakeHTTPClient{
headResp: &http.Response{
c: fakeHTTPClient(
&http.Response{
Status: http.StatusText(http.StatusNotFound),
StatusCode: http.StatusNotFound,
},
},
}, nil,
),
isErr: true,
},
{
......@@ -98,11 +119,40 @@ func Test_defaultGitHub_ValidateURL(t *testing.T) {
}
}
type fakeHTTPClient struct {
headResp *http.Response
headErr error
type mockTransport struct {
roundTrip func(req *http.Request) (*http.Response, error)
}
func (c *fakeHTTPClient) Head(string) (*http.Response, error) {
return c.headResp, c.headErr
func (f *mockTransport) RoundTrip(req *http.Request) (*http.Response, error) {
return f.roundTrip(req)
}
// Ensure httpClient propogates into vendor GitHub client
func Test_defaultGitHub_client(t *testing.T) {
var called bool
transport := &mockTransport{
roundTrip: func(req *http.Request) (*http.Response, error) {
called = true
return nil, errors.New("N/A")
},
}
httpClient := &http.Client{
Transport: transport,
}
wrapper := NewGitHub(httpClient)
dgh, ok := wrapper.(*defaultGitHub)
require.Truef(t, ok, "unexpected type: %T", wrapper)
os.Setenv("GITHUB_TOKEN", "")
github := dgh.client()
ctx := context.Background()
_, _, _ = github.Repositories.GetCommitSHA1(ctx, "ksonnet", "ksonnet", "master", "")
assert.True(t, called, "custom http client not called")
called = false
// Test with GITHUB_TOKEN
os.Setenv("GITHUB_TOKEN", "foobar")
github = dgh.client()
_, _, _ = github.Repositories.GetCommitSHA1(ctx, "ksonnet", "ksonnet", "master", "")
assert.True(t, called, "custom http client not called (with GITHUB_TOKEN)")
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment