diff --git a/check/controls.go b/check/controls.go
index 86828de..21d95d9 100644
--- a/check/controls.go
+++ b/check/controls.go
@@ -15,10 +15,13 @@
package check
import (
+ "bytes"
"encoding/json"
+ "encoding/xml"
"fmt"
"github.com/golang/glog"
+ "github.com/onsi/ginkgo/reporters"
"gopkg.in/yaml.v2"
)
@@ -132,6 +135,58 @@ func (controls *Controls) JSON() ([]byte, error) {
return json.Marshal(controls)
}
+// JUnit encodes the results of last run to JUnit.
+func (controls *Controls) JUnit() ([]byte, error) {
+ suite := reporters.JUnitTestSuite{
+ Name: controls.Text,
+ TestCases: []reporters.JUnitTestCase{},
+ Tests: controls.Summary.Pass + controls.Summary.Fail + controls.Summary.Info + controls.Summary.Warn,
+ Failures: controls.Summary.Fail,
+ }
+ for _, g := range controls.Groups {
+ for _, check := range g.Checks {
+ jsonCheck := ""
+ jsonBytes, err := json.Marshal(check)
+ if err != nil {
+ jsonCheck = fmt.Sprintf("Failed to marshal test into JSON: %v. Test as text: %#v", err, check)
+ } else {
+ jsonCheck = string(jsonBytes)
+ }
+ tc := reporters.JUnitTestCase{
+ Name: fmt.Sprintf("%v %v", check.ID, check.Text),
+ ClassName: g.Text,
+
+ // Store the entire json serialization as system out so we don't lose data in cases where deeper debugging is necessary.
+ SystemOut: jsonCheck,
+ }
+
+ switch check.State {
+ case FAIL:
+ tc.FailureMessage = &reporters.JUnitFailureMessage{Message: check.Remediation}
+ case WARN, INFO:
+ // WARN and INFO are two different versions of skipped tests. Either way it would be a false positive/negative to report
+ // it any other way.
+ tc.Skipped = &reporters.JUnitSkipped{}
+ case PASS:
+ default:
+ glog.Warningf("Unrecognized state %s", check.State)
+ }
+
+ suite.TestCases = append(suite.TestCases, tc)
+ }
+ }
+
+ var b bytes.Buffer
+ encoder := xml.NewEncoder(&b)
+ encoder.Indent("", " ")
+ err := encoder.Encode(suite)
+ if err != nil {
+ return nil, fmt.Errorf("Failed to generate JUnit report: %s", err.Error())
+ }
+
+ return b.Bytes(), nil
+}
+
func summarize(controls *Controls, state State) {
switch state {
case PASS:
diff --git a/check/controls_test.go b/check/controls_test.go
index bcf14d5..973dcc5 100644
--- a/check/controls_test.go
+++ b/check/controls_test.go
@@ -15,11 +15,15 @@
package check
import (
+ "bytes"
+ "encoding/json"
+ "encoding/xml"
"io/ioutil"
"os"
"path/filepath"
"testing"
+ "github.com/onsi/ginkgo/reporters"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"gopkg.in/yaml.v2"
@@ -160,6 +164,125 @@ groups:
})
}
+func TestControls_JUnitIncludesJSON(t *testing.T) {
+ testCases := []struct {
+ desc string
+ input *Controls
+ expect []byte
+ }{
+ {
+ desc: "Serializes to junit",
+ input: &Controls{
+ Groups: []*Group{
+ {
+ ID: "g1",
+ Checks: []*Check{
+ {ID: "check1id", Text: "check1text", State: PASS},
+ },
+ },
+ },
+ },
+ expect: []byte(`
+
+ {"test_number":"check1id","test_desc":"check1text","audit":"","AuditConfig":"","type":"","remediation":"","test_info":null,"status":"PASS","actual_value":"","scored":false,"expected_result":""}
+
+`),
+ }, {
+ desc: "Summary values come from summary not checks",
+ input: &Controls{
+ Summary: Summary{
+ Fail: 99,
+ Pass: 100,
+ Warn: 101,
+ Info: 102,
+ },
+ Groups: []*Group{
+ {
+ ID: "g1",
+ Checks: []*Check{
+ {ID: "check1id", Text: "check1text", State: PASS},
+ },
+ },
+ },
+ },
+ expect: []byte(`
+
+ {"test_number":"check1id","test_desc":"check1text","audit":"","AuditConfig":"","type":"","remediation":"","test_info":null,"status":"PASS","actual_value":"","scored":false,"expected_result":""}
+
+`),
+ }, {
+ desc: "Warn and Info are considered skips and failed tests properly reported",
+ input: &Controls{
+ Groups: []*Group{
+ {
+ ID: "g1",
+ Checks: []*Check{
+ {ID: "check1id", Text: "check1text", State: PASS},
+ {ID: "check2id", Text: "check2text", State: INFO},
+ {ID: "check3id", Text: "check3text", State: WARN},
+ {ID: "check4id", Text: "check4text", State: FAIL},
+ },
+ },
+ },
+ },
+ expect: []byte(`
+
+ {"test_number":"check1id","test_desc":"check1text","audit":"","AuditConfig":"","type":"","remediation":"","test_info":null,"status":"PASS","actual_value":"","scored":false,"expected_result":""}
+
+
+
+ {"test_number":"check2id","test_desc":"check2text","audit":"","AuditConfig":"","type":"","remediation":"","test_info":null,"status":"INFO","actual_value":"","scored":false,"expected_result":""}
+
+
+
+ {"test_number":"check3id","test_desc":"check3text","audit":"","AuditConfig":"","type":"","remediation":"","test_info":null,"status":"WARN","actual_value":"","scored":false,"expected_result":""}
+
+
+
+ {"test_number":"check4id","test_desc":"check4text","audit":"","AuditConfig":"","type":"","remediation":"","test_info":null,"status":"FAIL","actual_value":"","scored":false,"expected_result":""}
+
+`),
+ },
+ }
+ for _, tc := range testCases {
+ t.Run(tc.desc, func(t *testing.T) {
+ junitBytes, err := tc.input.JUnit()
+ if err != nil {
+ t.Fatalf("Failed to serialize to JUnit: %v", err)
+ }
+
+ var out reporters.JUnitTestSuite
+ if err := xml.Unmarshal(junitBytes, &out); err != nil {
+ t.Fatalf("Unable to deserialize from resulting JUnit: %v", err)
+ }
+
+ // Check that each check was serialized as json and stored as systemOut.
+ for iGroup, group := range tc.input.Groups {
+ for iCheck, check := range group.Checks {
+ jsonBytes, err := json.Marshal(check)
+ if err != nil {
+ t.Fatalf("Failed to serialize to JUnit: %v", err)
+ }
+
+ if out.TestCases[iGroup*iCheck+iCheck].SystemOut != string(jsonBytes) {
+ t.Errorf("Expected\n\t%v\n\tbut got\n\t%v",
+ out.TestCases[iGroup*iCheck+iCheck].SystemOut,
+ string(jsonBytes),
+ )
+ }
+ }
+ }
+
+ if !bytes.Equal(junitBytes, tc.expect) {
+ t.Errorf("Expected\n\t%v\n\tbut got\n\t%v",
+ string(tc.expect),
+ string(junitBytes),
+ )
+ }
+ })
+ }
+}
+
func assertEqualGroupSummary(t *testing.T, pass, fail, info, warn int, actual *Group) {
t.Helper()
assert.Equal(t, pass, actual.Pass)
diff --git a/cmd/common.go b/cmd/common.go
index 0f9debd..23957c7 100644
--- a/cmd/common.go
+++ b/cmd/common.go
@@ -114,8 +114,15 @@ func runChecks(nodetype check.NodeType) {
summary = controls.RunChecks(runner, filter)
- // if we successfully ran some tests and it's json format, ignore the warnings
- if (summary.Fail > 0 || summary.Warn > 0 || summary.Pass > 0 || summary.Info > 0) && jsonFmt {
+ if (summary.Fail > 0 || summary.Warn > 0 || summary.Pass > 0 || summary.Info > 0) && junitFmt {
+ out, err := controls.JUnit()
+ if err != nil {
+ exitWithError(fmt.Errorf("failed to output in JUnit format: %v", err))
+ }
+
+ PrintOutput(string(out), outputFile)
+ // if we successfully ran some tests and it's json format, ignore the warnings
+ } else if (summary.Fail > 0 || summary.Warn > 0 || summary.Pass > 0 || summary.Info > 0) && jsonFmt {
out, err := controls.JSON()
if err != nil {
exitWithError(fmt.Errorf("failed to output in JSON format: %v", err))
diff --git a/cmd/root.go b/cmd/root.go
index e277996..3eac65f 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -40,6 +40,7 @@ var (
cfgFile string
cfgDir string
jsonFmt bool
+ junitFmt bool
pgSQL bool
masterFile = "master.yaml"
nodeFile = "node.yaml"
@@ -91,6 +92,7 @@ func init() {
RootCmd.PersistentFlags().BoolVar(&noSummary, "nosummary", false, "Disable printing of summary section")
RootCmd.PersistentFlags().BoolVar(&noRemediations, "noremediations", false, "Disable printing of remediations section")
RootCmd.PersistentFlags().BoolVar(&jsonFmt, "json", false, "Prints the results as JSON")
+ RootCmd.PersistentFlags().BoolVar(&junitFmt, "junit", false, "Prints the results as JUnit")
RootCmd.PersistentFlags().BoolVar(&pgSQL, "pgsql", false, "Save the results to PostgreSQL")
RootCmd.PersistentFlags().BoolVar(&filterOpts.Scored, "scored", true, "Run the scored CIS checks")
RootCmd.PersistentFlags().BoolVar(&filterOpts.Unscored, "unscored", true, "Run the unscored CIS checks")
diff --git a/go.mod b/go.mod
index 97f3959..4081298 100644
--- a/go.mod
+++ b/go.mod
@@ -16,6 +16,7 @@ require (
github.com/mattn/go-colorable v0.0.0-20170210172801-5411d3eea597 // indirect
github.com/mattn/go-isatty v0.0.0-20170307163044-57fdcb988a5c // indirect
github.com/mattn/go-sqlite3 v1.10.0 // indirect
+ github.com/onsi/ginkgo v1.7.0
github.com/spf13/cobra v0.0.1
github.com/spf13/viper v1.4.0
github.com/stretchr/testify v1.3.0
diff --git a/go.sum b/go.sum
index ea57237..eade2f9 100644
--- a/go.sum
+++ b/go.sum
@@ -10,8 +10,6 @@ github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMx
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
-github.com/aquasecurity/kube-bench v0.0.29 h1:jn0odIPAx+OArSfGGjA529PxZSS4xps6gq8LlX4h5wk=
-github.com/aquasecurity/kube-bench v0.0.29/go.mod h1:OJtT6nbmq/4tkF3sIKHO8DIZz7PVXDwYlXJusc33R3Y=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
@@ -54,6 +52,7 @@ github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4er
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
@@ -70,10 +69,9 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmg
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/hashicorp/hcl v0.0.0-20171017181929-23c074d0eceb h1:1OvvPvZkn/yCQ3xBcM8y4020wdkMXPHLB4+NfoGWh4U=
-github.com/hashicorp/hcl v0.0.0-20171017181929-23c074d0eceb/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
@@ -97,8 +95,6 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lib/pq v0.0.0-20171126050459-83612a56d3dd h1:2RDaVc4/izhWyAvYxNm8c9saSyCDIxefNwOcqaH7pcU=
github.com/lib/pq v0.0.0-20171126050459-83612a56d3dd/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
-github.com/magiconair/properties v0.0.0-20171031211101-49d762b9817b h1:bR3tkU6ocnK5a0NsdgTMWc7sILt+BY0PceUYC6EpSqc=
-github.com/magiconair/properties v0.0.0-20171031211101-49d762b9817b/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-colorable v0.0.0-20170210172801-5411d3eea597 h1:hGizH4aMDFFt1iOA4HNKC13lqIBoCyxIjWcAnWIy7aU=
@@ -108,18 +104,16 @@ github.com/mattn/go-isatty v0.0.0-20170307163044-57fdcb988a5c/go.mod h1:M+lRXTBq
github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o=
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
-github.com/mitchellh/mapstructure v0.0.0-20171017171808-06020f85339e h1:PtGHLB3CX3TFPcksODQMxncoeQKWwCgTg0bJ40VLJP4=
-github.com/mitchellh/mapstructure v0.0.0-20171017171808-06020f85339e/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
-github.com/pelletier/go-toml v0.0.0-20171222114548-0131db6d737c h1:38Gz4xhAnFXimzmHWtvA13DKjvKbXA8OoCpUwCsfmAk=
-github.com/pelletier/go-toml v0.0.0-20171222114548-0131db6d737c/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
@@ -144,26 +138,16 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
-github.com/spf13/afero v0.0.0-20171228125011-57afd63c6860 h1:Sah2mqQfQuPUyJ+MJN2JevGfVjF80KsRLR5fcaERajg=
-github.com/spf13/afero v0.0.0-20171228125011-57afd63c6860/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
-github.com/spf13/cast v1.1.0 h1:0Rhw4d6C8J9VPu6cjZLIhZ8+aAOHcDvGeKn+cq5Aq3k=
-github.com/spf13/cast v1.1.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.1 h1:zZh3X5aZbdnoj+4XkaBxKfhO4ot82icYdhhREIAXIj8=
github.com/spf13/cobra v0.0.1/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
-github.com/spf13/jwalterweatherman v0.0.0-20170901151539-12bd96e66386 h1:zBoLErXXAvWnNsu+pWkRYl6Cx1KXmIfAVsIuYkPN6aY=
-github.com/spf13/jwalterweatherman v0.0.0-20170901151539-12bd96e66386/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
-github.com/spf13/pflag v0.0.0-20171106142849-4c012f6dcd95 h1:fBkxrj/ArtKnC3J1DOZhn3SYiVkVRFZC574bq2Ifa/0=
-github.com/spf13/pflag v0.0.0-20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/spf13/viper v1.0.0 h1:RUA/ghS2i64rlnn4ydTfblY8Og8QzcPtCcHvgMn+w/I=
-github.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM=
github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU=
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -199,6 +183,7 @@ golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -239,8 +224,10 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=