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=