Skip to content

Commit 06d1664

Browse files
committed
Revamp server validation feature
1 parent d23aacd commit 06d1664

File tree

6 files changed

+176
-46
lines changed

6 files changed

+176
-46
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
55
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
66

77
## [Unreleased]
8+
- Revamped support for `--validate-server` (short `-s`)
9+
- Requires the use of server base path(s) on the client.
10+
- Localhost is now always allowed on all known base paths.
11+
- Support for proxy headers (e.g. `X-Forwarded-Host`).
812
- Better support for resolving relative path references.
913
- Be more resilient to parser panics when using `--watch`
1014
- Update Docker build to use Go 1.12 and Go modules.

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ A simple, quick, cross-platform API mock server that returns examples specified
1010
- Example: `Accept: application/*`
1111
- Prefer header to select response to test specific cases
1212
- Example: `Prefer: status=409`
13-
- Server name validation (enabled with `--validate-server`)
13+
- Server validation (enabled with `--validate-server`)
14+
- Validates scheme, hostname/port, and base path
15+
- Supports `localhost` out of the box
1416
- Request parameter & body validation (enabled with `--validate-request`)
1517
- Configuration via:
1618
- Files (`/etc/apisprout/config.json|yaml`)
@@ -39,7 +41,7 @@ docker run -p 8000:8000 danielgtaylor/apisprout http://example.com/my-api.yaml
3941
Configuration can be passed via environment variables, e.g. setting `SPROUT_VALIDATE_REQUEST=1`, or by passing commandline flags. It is also possible to use a local API description file via [Docker Volumes](https://docs.docker.com/storage/volumes/):
4042

4143
```
42-
# Remeber to put the full path to local archive YAML in -v
44+
# Remember to put the full path to local archive YAML in -v
4345
docker run -p 8000:8000 -v $FULLPATH/localfile.yaml:/api.yaml danielgtaylor/apisprout /api.yaml
4446
```
4547

apisprout.go

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ func main() {
109109
flags := root.PersistentFlags()
110110

111111
addParameter(flags, "port", "p", 8000, "HTTP port")
112-
addParameter(flags, "validate-server", "", false, "Check hostname against configured servers")
112+
addParameter(flags, "validate-server", "s", false, "Check scheme/hostname/basepath against configured servers")
113113
addParameter(flags, "validate-request", "", false, "Check request data structure")
114114
addParameter(flags, "watch", "w", false, "Reload when input file changes")
115115
addParameter(flags, "disable-cors", "", false, "Disable CORS headers")
@@ -215,6 +215,45 @@ func getExample(negotiator *ContentNegotiator, prefer string, op *openapi3.Opera
215215
return 0, "", nil, ErrNoExample
216216
}
217217

218+
// addLocalServers will ensure that requests to localhost are always allowed
219+
// even if not specified in the OpenAPI document.
220+
func addLocalServers(swagger *openapi3.Swagger) error {
221+
seen := make(map[string]bool)
222+
for _, s := range swagger.Servers {
223+
seen[s.URL] = true
224+
}
225+
226+
lservers := make([]*openapi3.Server, 0, len(swagger.Servers))
227+
for _, s := range swagger.Servers {
228+
u, err := url.Parse(s.URL)
229+
if err != nil {
230+
return err
231+
}
232+
233+
if u.Hostname() != "localhost" {
234+
u.Scheme = "http"
235+
u.Host = fmt.Sprintf("localhost:%d", viper.GetInt("port"))
236+
237+
ls := &openapi3.Server{
238+
URL: u.String(),
239+
Description: s.Description,
240+
Variables: s.Variables,
241+
}
242+
243+
if !seen[ls.URL] {
244+
lservers = append(lservers, ls)
245+
seen[ls.URL] = true
246+
}
247+
}
248+
}
249+
250+
if len(lservers) != 0 {
251+
swagger.Servers = append(swagger.Servers, lservers...)
252+
}
253+
254+
return nil
255+
}
256+
218257
// Load the OpenAPI document and create the router.
219258
func load(uri string, data []byte) (swagger *openapi3.Swagger, router *openapi3filter.Router, err error) {
220259
defer func() {
@@ -247,6 +286,11 @@ func load(uri string, data []byte) (swagger *openapi3.Swagger, router *openapi3f
247286
// Clear the server list so no validation happens. Note: this has a side
248287
// effect of no longer parsing any server-declared parameters.
249288
swagger.Servers = make([]*openapi3.Server, 0)
289+
} else {
290+
// Special-case localhost to always be allowed for local testing.
291+
if err = addLocalServers(swagger); err != nil {
292+
return
293+
}
250294
}
251295

252296
// Create a new router using the OpenAPI document's declared paths.
@@ -406,6 +450,26 @@ func server(cmd *cobra.Command, args []string) {
406450
}
407451

408452
info := fmt.Sprintf("%s %v", req.Method, req.URL)
453+
454+
// Set up the request, handling potential proxy headers
455+
req.URL.Host = req.Host
456+
fHost := req.Header.Get("X-Forwarded-Host")
457+
if fHost != "" {
458+
req.URL.Host = fHost
459+
}
460+
461+
req.URL.Scheme = "http"
462+
if req.Header.Get("X-Forwarded-Proto") == "https" ||
463+
req.Header.Get("X-Forwarded-Scheme") == "https" ||
464+
strings.Contains(req.Header.Get("Forwarded"), "proto=https") {
465+
req.URL.Scheme = "https"
466+
}
467+
468+
if viper.GetBool("validate-server") {
469+
// Use the scheme/host in the log message since we are validating it.
470+
info = fmt.Sprintf("%s %v", req.Method, req.URL)
471+
}
472+
409473
route, pathParams, err := router.FindRoute(req.Method, req.URL)
410474
if err != nil {
411475
log.Printf("ERROR: %s => %v", info, err)
@@ -501,6 +565,16 @@ func server(cmd *cobra.Command, args []string) {
501565
w.Write(encoded)
502566
})
503567

504-
fmt.Printf("🌱 Sprouting %s on port %d\n", swagger.Info.Title, viper.GetInt("port"))
568+
fmt.Printf("🌱 Sprouting %s on port %d", swagger.Info.Title, viper.GetInt("port"))
569+
570+
if viper.GetBool("validate-server") && len(swagger.Servers) != 0 {
571+
fmt.Printf(" with valid servers:\n")
572+
for _, s := range swagger.Servers {
573+
fmt.Println("• " + s.URL)
574+
}
575+
} else {
576+
fmt.Printf("\n")
577+
}
578+
505579
http.ListenAndServe(fmt.Sprintf(":%d", viper.GetInt("port")), nil)
506580
}

apisprout_test.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,83 @@
11
package main
2+
3+
import (
4+
"testing"
5+
6+
"github.com/getkin/kin-openapi/openapi3"
7+
"github.com/spf13/viper"
8+
"github.com/stretchr/testify/assert"
9+
)
10+
11+
var localServerTests = []struct {
12+
name string
13+
in []string
14+
out []string
15+
}{
16+
{
17+
"No servers",
18+
[]string{},
19+
[]string{},
20+
},
21+
{
22+
"Same path",
23+
[]string{
24+
"https://api.example.com/v1",
25+
"https://beta.api.example.com/v1",
26+
},
27+
[]string{
28+
"https://api.example.com/v1",
29+
"https://beta.api.example.com/v1",
30+
"http://localhost:8000/v1",
31+
},
32+
},
33+
{
34+
"Includes localhost already",
35+
[]string{
36+
"https://api.example.com/v1",
37+
"http://localhost:8000/v1",
38+
},
39+
[]string{
40+
"https://api.example.com/v1",
41+
"http://localhost:8000/v1",
42+
},
43+
},
44+
{
45+
"Invalid URL",
46+
[]string{
47+
"http://192.168.0.%31/",
48+
},
49+
[]string{},
50+
},
51+
}
52+
53+
func TestAddLocalServers(t *testing.T) {
54+
viper.SetDefault("port", 8000)
55+
for _, tt := range localServerTests {
56+
t.Run(tt.name, func(t *testing.T) {
57+
servers := make([]*openapi3.Server, len(tt.in))
58+
for i, u := range tt.in {
59+
servers[i] = &openapi3.Server{
60+
URL: u,
61+
}
62+
}
63+
64+
s := &openapi3.Swagger{
65+
Servers: servers,
66+
}
67+
68+
err := addLocalServers(s)
69+
if len(tt.in) > 0 && len(tt.out) == 0 {
70+
assert.Error(t, err)
71+
return
72+
}
73+
assert.NoError(t, err)
74+
75+
results := make([]string, 0, len(tt.out))
76+
for _, server := range s.Servers {
77+
results = append(results, server.URL)
78+
}
79+
80+
assert.Equal(t, tt.out, results)
81+
})
82+
}
83+
}

go.mod

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,17 @@ module github.com/danielgtaylor/apisprout
33
go 1.12
44

55
require (
6-
github.com/coreos/etcd v3.3.12+incompatible // indirect
7-
github.com/davecgh/go-spew v1.1.1
6+
github.com/BurntSushi/toml v0.3.1 // indirect
87
github.com/fsnotify/fsnotify v1.4.7
98
github.com/getkin/kin-openapi v0.1.1-0.20190210195911-82a13f94c08e
10-
github.com/ghodss/yaml v1.0.0
119
github.com/gobwas/glob v0.2.3
12-
github.com/hashicorp/hcl v1.0.0
13-
github.com/inconshreveable/mousetrap v1.0.0
14-
github.com/kr/pty v1.1.3 // indirect
15-
github.com/magiconair/properties v1.8.0
16-
github.com/mitchellh/mapstructure v1.1.2
17-
github.com/pelletier/go-toml v1.2.0
10+
github.com/inconshreveable/mousetrap v1.0.0 // indirect
1811
github.com/pkg/errors v0.8.1
19-
github.com/pmezard/go-difflib v1.0.0
20-
github.com/spf13/afero v1.2.1
21-
github.com/spf13/cast v1.3.0
12+
github.com/spf13/afero v1.2.1 // indirect
2213
github.com/spf13/cobra v0.0.3
23-
github.com/spf13/jwalterweatherman v1.0.0
2414
github.com/spf13/pflag v1.0.3
2515
github.com/spf13/viper v1.3.1
26-
github.com/stretchr/objx v0.1.1 // indirect
2716
github.com/stretchr/testify v1.3.0
28-
github.com/ugorji/go/codec v0.0.0-20190204201341-e444a5086c43 // indirect
29-
golang.org/x/crypto v0.0.0-20190227175134-215aa809caaf // indirect
30-
golang.org/x/sys v0.0.0-20190226215855-775f8194d0f9
31-
golang.org/x/text v0.3.0
17+
golang.org/x/sys v0.0.0-20190226215855-775f8194d0f9 // indirect
3218
gopkg.in/yaml.v2 v2.2.2
3319
)

go.sum

Lines changed: 6 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
1+
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
2+
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
13
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
24
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
3-
github.com/coreos/etcd v3.3.12+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
45
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
56
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
67
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
78
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
89
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
910
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
1011
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
11-
github.com/getkin/kin-openapi v0.0.0-20181003150400-44c981756c70 h1:HtMZviFRTPQGdNPcNDLHbuzU4YQZcJIwqJg4IoHyCvY=
12-
github.com/getkin/kin-openapi v0.0.0-20181003150400-44c981756c70/go.mod h1:+0ZtELZf+SlWH8ZdA/IeFb3L/PKOKJx8eGxAlUZ/sOU=
13-
github.com/getkin/kin-openapi v0.1.0 h1:uLHHTCEksmwf3frJv/GZEz9PX5KNT9qdXphr0j3n4P8=
14-
github.com/getkin/kin-openapi v0.1.0/go.mod h1:+0ZtELZf+SlWH8ZdA/IeFb3L/PKOKJx8eGxAlUZ/sOU=
1512
github.com/getkin/kin-openapi v0.1.1-0.20190210195911-82a13f94c08e h1:Dt2Of/HBY6htbODmBF2eBtlo2VdfOeeWb+qYZDvgsoU=
1613
github.com/getkin/kin-openapi v0.1.1-0.20190210195911-82a13f94c08e/go.mod h1:V1z9xl9oF5Wt7v32ne4FmiF1alpS4dM6mNzoywPOXlk=
1714
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
@@ -20,16 +17,15 @@ github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
2017
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
2118
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
2219
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
20+
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
2321
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
22+
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
2423
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
2524
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
26-
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
25+
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
2726
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
2827
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
2928
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
30-
github.com/mitchellh/mapstructure v1.0.0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
31-
github.com/mitchellh/mapstructure v1.1.1 h1:0fcGQkeJPHl7DauilpdNG27ZxXHDSg+rbbTpfpniZd8=
32-
github.com/mitchellh/mapstructure v1.1.1/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
3329
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
3430
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
3531
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
@@ -42,44 +38,30 @@ github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
4238
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
4339
github.com/spf13/afero v1.2.1 h1:qgMbHoJbPbw579P+1zVY+6n4nIFuIchaIjzZ/I/Yq8M=
4440
github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
45-
github.com/spf13/cast v1.2.0 h1:HHl1DSRbEQN2i8tJmtS6ViPyHx35+p51amrdsiTCrkg=
46-
github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
4741
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
4842
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
4943
github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8=
5044
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
5145
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
5246
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
53-
github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
5447
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
5548
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
56-
github.com/spf13/viper v1.2.1 h1:bIcUwXqLseLF3BDAZduuNfekWG87ibtFxi59Bq+oI9M=
57-
github.com/spf13/viper v1.2.1/go.mod h1:P4AexN0a+C9tGAnUFNwDMYYZv3pjFuvmeiMyKRaNVlI=
5849
github.com/spf13/viper v1.3.1 h1:5+8j8FTpnFV4nEImW/ofkzEt8VoOiLXxdYIDsB73T38=
5950
github.com/spf13/viper v1.3.1/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
6051
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
61-
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
6252
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
6353
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
6454
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
65-
github.com/ugorji/go v1.1.2/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
6655
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
67-
github.com/ugorji/go/codec v0.0.0-20190204201341-e444a5086c43/go.mod h1:iT03XoTwV7xq/+UGwKO3UbC1nNNlopQiY61beSdrtOA=
6856
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
6957
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
70-
golang.org/x/crypto v0.0.0-20190227175134-215aa809caaf/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
71-
golang.org/x/sys v0.0.0-20180906133057-8cf3aee42992/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
72-
golang.org/x/sys v0.0.0-20181003145944-af653ce8b74f h1:zAtpFwFDtnvBWPPelq8CSiqRN1wrIzMUk9dwzbpjpNM=
73-
golang.org/x/sys v0.0.0-20181003145944-af653ce8b74f/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
7458
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
75-
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
7659
golang.org/x/sys v0.0.0-20190226215855-775f8194d0f9 h1:N26gncmS+iqc/W/SKhX3ElI5pkt72XYoRLgi5Z70LSc=
7760
golang.org/x/sys v0.0.0-20190226215855-775f8194d0f9/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
7861
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
7962
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
8063
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
64+
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
8165
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
82-
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
83-
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
8466
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
8567
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

0 commit comments

Comments
 (0)