Skip to content

Commit

Permalink
add "tls" config section for specifiying client certs or skiping tls …
Browse files Browse the repository at this point in the history
…verification
  • Loading branch information
zaquestion committed Dec 11, 2019
1 parent 0e33267 commit 3f9088d
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 30 deletions.
5 changes: 1 addition & 4 deletions cmd/root_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,7 @@ func TestMain(m *testing.M) {
if err != nil {
log.Fatal(err)
}
lab.Init(
config["host"].(string),
u.Username,
config["token"].(string))
lab.Init(config["host"].(string), u.Username, config["token"].(string), false)

code := m.Run()

Expand Down
94 changes: 80 additions & 14 deletions internal/gitlab/gitlab.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@
package gitlab

import (
"crypto/tls"
"crypto/x509"
"fmt"
"io"
"io/ioutil"
"log"
"net"
"net/http"
"os"
"path/filepath"
"strings"
"time"

"github.com/pkg/errors"
gitlab "github.com/xanzy/go-gitlab"
Expand Down Expand Up @@ -42,17 +46,79 @@ func User() string {
}

// Init initializes a gitlab client for use throughout lab.
func Init(_host, _user, _token string) {
func Init(_host, _user, _token string, allowInsecure bool) {
if len(_host) > 0 && _host[len(_host)-1 : len(_host)][0] == '/' {
_host = _host[0 : len(_host)-1]
}
host = _host
user = _user
token = _token
lab = gitlab.NewClient(nil, token)

httpClient := &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}).DialContext,
ForceAttemptHTTP2: true,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
TLSClientConfig: &tls.Config{
InsecureSkipVerify: allowInsecure,
},
},
}

lab = gitlab.NewClient(httpClient, token)
lab.SetBaseURL(host + "/api/v4")
}

func InitWithClientCerts(_host, _user, _token, caFile, clientKeyFile, clientCertFile string) error {
caCert, err := ioutil.ReadFile(caFile)
if err != nil {
return err
}
// use system cert pool as a baseline
caCertPool, err := x509.SystemCertPool()
if err != nil {
return err
}
caCertPool.AppendCertsFromPEM(caCert)

cert, err := tls.LoadX509KeyPair(clientCertFile, clientKeyFile)
if err != nil {
return err
}

httpClient := &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}).DialContext,
ForceAttemptHTTP2: true,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
TLSClientConfig: &tls.Config{
RootCAs: caCertPool,
Certificates: []tls.Certificate{cert},
},
},
}

lab = gitlab.NewClient(httpClient, token)
lab.SetBaseURL(host + "/api/v4")
return nil
}

// Defines filepath for default GitLab templates
const (
TmplMR = "merge_request_templates/default.md"
Expand Down Expand Up @@ -170,18 +236,18 @@ func MRCreate(project string, opts *gitlab.CreateMergeRequestOptions) (string, e

// MRCreateNote adds a note to a merge request on GitLab
func MRCreateNote(project string, mrNum int, opts *gitlab.CreateMergeRequestNoteOptions) (string, error) {
p, err := FindProject(project)
if err != nil {
return "", err
}

note, _, err := lab.Notes.CreateMergeRequestNote(p.ID, mrNum, opts)
if err != nil {
return "", err
}
// Unlike MR, Note has no WebURL property, so we have to create it
// ourselves from the project, noteable id and note id
return fmt.Sprintf("%s/merge_requests/%d#note_%d", p.WebURL, note.NoteableIID, note.ID), nil
p, err := FindProject(project)
if err != nil {
return "", err
}

note, _, err := lab.Notes.CreateMergeRequestNote(p.ID, mrNum, opts)
if err != nil {
return "", err
}
// Unlike MR, Note has no WebURL property, so we have to create it
// ourselves from the project, noteable id and note id
return fmt.Sprintf("%s/merge_requests/%d#note_%d", p.WebURL, note.NoteableIID, note.ID), nil
}

// MRGet retrieves the merge request from GitLab project
Expand Down
5 changes: 1 addition & 4 deletions internal/gitlab/gitlab_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,7 @@ func TestMain(m *testing.M) {
log.Fatal(err)
}

Init(
config["host"].(string),
u.Username,
config["token"].(string))
Init(config["host"].(string), u.Username, config["token"].(string), false)

code := m.Run()

Expand Down
76 changes: 68 additions & 8 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
// version gets set on releases during build by goreleaser.
var version = "master"

func loadConfig() (string, string, string) {
func loadConfig() (string, string, string, bool) {
home, err := os.UserHomeDir()
if err != nil {
log.Fatal(err)
Expand Down Expand Up @@ -45,18 +45,21 @@ func loadConfig() (string, string, string) {
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
viper.AutomaticEnv()

var tlsSkipVerify bool
tlsSkipVerify = viper.GetBool("tls.skip_verify")

host, user, token := viper.GetString("core.host"), viper.GetString("core.user"), viper.GetString("core.token")
if host != "" && user != "" && token != "" {
return host, user, token
return host, user, token, tlsSkipVerify
} else if host != "" && token != "" {
user = getUser(host, token)
return host, user, token
return host, user, token, tlsSkipVerify
}

// Attempt to auto-configure for GitLab CI
host, user, token = config.CI()
if host != "" && user != "" && token != "" {
return host, user, token
return host, user, token, tlsSkipVerify
}

if _, ok := viper.ReadInConfig().(viper.ConfigFileNotFoundError); ok {
Expand All @@ -69,9 +72,9 @@ func loadConfig() (string, string, string) {
}
}

c := viper.AllSettings()["core"]
c := viper.AllSettings()
var cfg map[string]interface{}
switch v := c.(type) {
switch v := c["core"].(type) {
// Most run this is the type
case []map[string]interface{}:
cfg = v[0]
Expand All @@ -88,6 +91,20 @@ func loadConfig() (string, string, string) {
}
}

var tls map[string]interface{}
switch v := c["tls"].(type) {
// Most run this is the type
case []map[string]interface{}:
tls = v[0]
// On the first run when the cfg is created it comes in as this type
// for whatever reason
case map[string]interface{}:
tls = v
}
if v, ok := tls["skip_verify"]; ok {
tlsSkipVerify = v.(bool)
}

// Set environment overrides
// Note: the code below that uses `cfg["host"]` to access these values
// is tough to simplify since cfg["host"] is accessing the array "core"
Expand All @@ -99,11 +116,47 @@ func loadConfig() (string, string, string) {
if v := viper.GetString("core.token"); v != "" {
cfg["token"] = v
}
if v := viper.Get("tls.skip_verify"); v != nil {
tlsSkipVerify = v.(string) == "true"
}
host = cfg["host"].(string)
token = cfg["token"].(string)
user = getUser(host, token)
viper.Set("core.user", user)
return host, user, token
return host, user, token, tlsSkipVerify
}

func loadTLSCerts() (string, string, string) {
c := viper.AllSettings()

var tls map[string]interface{}
switch v := c["tls"].(type) {
// Most run this is the type
case []map[string]interface{}:
tls = v[0]
// On the first run when the cfg is created it comes in as this type
// for whatever reason
case map[string]interface{}:
tls = v
}

for _, v := range []string{"ca_file", "cert_file", "key_file"} {
if _, ok := tls[v]; !ok {
return "", "", ""
}
}

if v := viper.GetString("tls.ca_file"); v != "" {
tls["ca_file"] = v
}
if v := viper.GetString("tls.cert_file"); v != "" {
tls["cert_file"] = v
}
if v := viper.GetString("tls.ca_file"); v != "" {
tls["key_file"] = v
}

return tls["ca_file"].(string), tls["cert_file"].(string), tls["key_file"].(string)
}

func getUser(host, token string) string {
Expand All @@ -120,7 +173,14 @@ func main() {
log.SetFlags(log.LstdFlags | log.Lshortfile)
cmd.Version = version
if !skipInit() {
lab.Init(loadConfig())
ca, cert, key := loadTLSCerts()
h, u, t, skipVerify := loadConfig()

if ca != "" && cert != "" && key != "" {
lab.InitWithClientCerts(h, u, t, ca, key, cert)
} else {
lab.Init(h, u, t, skipVerify)
}
}
cmd.Execute()
}
Expand Down

0 comments on commit 3f9088d

Please sign in to comment.