From 66a4e5122a2d810ada2f23af803d1e44256dd260 Mon Sep 17 00:00:00 2001 From: Nikhita Raghunath Date: Wed, 22 Nov 2017 16:34:36 +0530 Subject: [PATCH] bump(go-openapi/validate): d509235108fcf6ab4913d2dcb3a2260c0db2108e --- Godeps/Godeps.json | 2 +- .../github.com/go-openapi/validate/.drone.sec | 1 - .../github.com/go-openapi/validate/.drone.yml | 40 --------- .../go-openapi/validate/.pullapprove.yml | 13 --- .../go-openapi/validate/.travis.yml | 22 +++++ .../github.com/go-openapi/validate/README.md | 2 +- .../github.com/go-openapi/validate/formats.go | 5 +- .../go-openapi/validate/object_validator.go | 73 ++++++++++++--- .../github.com/go-openapi/validate/result.go | 30 ++++++- .../github.com/go-openapi/validate/schema.go | 48 ++++++++-- .../go-openapi/validate/schema_props.go | 17 +++- .../go-openapi/validate/slice_validator.go | 3 + vendor/github.com/go-openapi/validate/spec.go | 88 +++++++++++++++---- vendor/github.com/go-openapi/validate/type.go | 19 ++-- .../go-openapi/validate/update-fixtures.sh | 15 ++++ .../go-openapi/validate/validator.go | 33 +++++-- .../github.com/go-openapi/validate/values.go | 6 +- 17 files changed, 301 insertions(+), 116 deletions(-) delete mode 100644 vendor/github.com/go-openapi/validate/.drone.sec delete mode 100644 vendor/github.com/go-openapi/validate/.drone.yml delete mode 100644 vendor/github.com/go-openapi/validate/.pullapprove.yml create mode 100644 vendor/github.com/go-openapi/validate/.travis.yml create mode 100755 vendor/github.com/go-openapi/validate/update-fixtures.sh diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 12c252b516b..6a90e23829d 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -1263,7 +1263,7 @@ }, { "ImportPath": "github.com/go-openapi/validate", - "Rev": "deaf2c9013bc1a7f4c774662259a506ba874d80f" + "Rev": "d509235108fcf6ab4913d2dcb3a2260c0db2108e" }, { "ImportPath": "github.com/godbus/dbus", diff --git a/vendor/github.com/go-openapi/validate/.drone.sec b/vendor/github.com/go-openapi/validate/.drone.sec deleted file mode 100644 index 64bfa2ef6e9..00000000000 --- a/vendor/github.com/go-openapi/validate/.drone.sec +++ /dev/null @@ -1 +0,0 @@ -eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.lisG21ATunZSCBP6vaqK_AZCIR18tN563RdqkAb6PGOipqTeg8R7VwZQIeDqS-2Vond6NX_KSC_D_uxxv0hBf2DiGXmwMUmP4nRXrsmbzT2qQKKIHYRDC_6jb2-FSfK14ezIe1Q07UiiJecDsN3CFEccS8E68Tdnp78p7yDwbTvpumnZmwYfyhlImtjFQv2YpyFVsjEHWK0R4e9T3ONQWcx6D2rSoxABbutrS03QwsJhHCeD9joL_gxfkFKm3CW8yWPSk2QYtx_Q1hu-tZR4IPb2tQPXPX3mtyhwBqziWgmJRDFCEjlCO5aCobiMm_9K5X05gue_DcgW163zh1P9jg.nleER2An8CUn_OuR.b77RFEFp0gC8j5yCAoARNKYmQIvWq99ibmf5ffJgdhQBF3sRYJLt_XflJ_2lsaiFOxvc45T2fnkMVy2lHFcri7F9f1BRiT_0AcDthxsecGzG8BZ9QvaM6b4Dn0rhjrOq8rsF0m3ZnbPBkkg3LV5EkbHWstMo2fgJPJhJswlGWhqJPJBDecG1nMBC8SMH32X-zVlSM-BLiaghvOGNxyb_RLZJZ3CLczIdQ2JO2UeYkOGCPGzernvkHDMpqQXc-8cmulDdHgCy87qFLy5ttGFgYbnTm92h_ChOGKZixeX0PL0pQY5wXd2xTO7Tg_Ov5E5FoVwIkwOextedVsF9iz_b_mwtCY3LXrvbJTW7zWrwBVsVyAXxT5iu0HyQ3tBVxT2GxS-yM5ApqLozcZCQg9flMyfSgThu82FfzEr0fI5vKw8zo0GdO4GBuVSppM9m6ToG6hlwyHD9g2YTZw9068hyq1_kZQhugJRjgGbpa2gyGqzx16fg0zVoupVIiq5KfvRlAQFeOVVjQwb0BWf25tJUj5tV3O9ge6dbKSXizEca33FJJwJWoXhd7DCREXUU9pBz06NCCf495BGoVbq3oLPDQc2mpcuy0XAPxSwXcc5Ts8DNs7MrxBlYdw81wMXuztIpOY4.XjKlMWl_H40XszToi2VU5g \ No newline at end of file diff --git a/vendor/github.com/go-openapi/validate/.drone.yml b/vendor/github.com/go-openapi/validate/.drone.yml deleted file mode 100644 index cfe9c7c3005..00000000000 --- a/vendor/github.com/go-openapi/validate/.drone.yml +++ /dev/null @@ -1,40 +0,0 @@ -clone: - path: github.com/go-openapi/validate - -matrix: - GO_VERSION: - - "1.6" - -build: - integration: - image: golang:$$GO_VERSION - pull: true - commands: - - go get -u github.com/axw/gocov/gocov - - go get -u gopkg.in/matm/v1/gocov-html - - go get -u github.com/cee-dub/go-junit-report - - go get -u github.com/stretchr/testify/assert - - go get -u gopkg.in/yaml.v2 - - go get -u github.com/go-openapi/analysis - - go get -u github.com/go-openapi/errors - - go get -u github.com/go-openapi/loads - - go get -u github.com/go-openapi/strfmt - - go get -u github.com/go-openapi/runtime - - go test -race - - go test -v -cover -coverprofile=coverage.out -covermode=count - -notify: - slack: - channel: bots - webhook_url: $$SLACK_URL - username: drone - -publish: - coverage: - server: https://coverage.vmware.run - token: $$GITHUB_TOKEN - # threshold: 70 - # must_increase: true - when: - matrix: - GO_VERSION: "1.6" diff --git a/vendor/github.com/go-openapi/validate/.pullapprove.yml b/vendor/github.com/go-openapi/validate/.pullapprove.yml deleted file mode 100644 index 5ec183e2244..00000000000 --- a/vendor/github.com/go-openapi/validate/.pullapprove.yml +++ /dev/null @@ -1,13 +0,0 @@ -approve_by_comment: true -approve_regex: '^(:shipit:|:\+1:|\+1|LGTM|lgtm|Approved)' -reject_regex: ^[Rr]ejected -reset_on_push: false -reviewers: - members: - - casualjim - - chancez - - frapposelli - - vburenin - - pytlesk4 - name: pullapprove - required: 1 diff --git a/vendor/github.com/go-openapi/validate/.travis.yml b/vendor/github.com/go-openapi/validate/.travis.yml new file mode 100644 index 00000000000..6eeb6f62675 --- /dev/null +++ b/vendor/github.com/go-openapi/validate/.travis.yml @@ -0,0 +1,22 @@ +language: go +go: +- 1.7 +install: +- go get -u github.com/axw/gocov/gocov +- go get -u gopkg.in/matm/v1/gocov-html +- go get -u github.com/cee-dub/go-junit-report +- go get -u github.com/stretchr/testify/assert +- go get -u github.com/kr/pretty +- go get -u gopkg.in/yaml.v2 +- go get -u github.com/go-openapi/analysis +- go get -u github.com/go-openapi/errors +- go get -u github.com/go-openapi/loads +- go get -u github.com/go-openapi/strfmt +- go get -u github.com/go-openapi/runtime +script: +- go test -v -race -cover -coverprofile=coverage.txt -covermode=atomic +after_success: +- bash <(curl -s https://codecov.io/bash) +notifications: + slack: + secure: EmObnQuM9Mw8J9vpFaKKHqSMN4Wsr/A9+v7ewAD5cEhA0T1P4m7MbJMiJOhxUhj/X+BFh2DamW+P2lT8mybj5wg8wnkQ2BteKA8Tawi6f9PRw2NRheO8tAi8o/npLnlmet0kc93mn+oLuqHw36w4+j5mkOl2FghkfGiUVhwrhkCP7KXQN+3TU87e+/HzQumlJ3nsE+6terVxkH3PmaUTsS5ONaODZfuxFpfb7RsoEl3skHf6d+tr+1nViLxxly7558Nc33C+W1mr0qiEvMLZ+kJ/CpGWBJ6CUJM3jm6hNe2eMuIPwEK2hxZob8c7n22VPap4K6a0bBRoydoDXaba+2sD7Ym6ivDO/DVyL44VeBBLyIiIBylDGQdZH+6SoWm90Qe/i7tnY/T5Ao5igT8f3cfQY1c3EsTfqmlDfrhmACBmwSlgkdVBLTprHL63JMY24LWmh4jhxsmMRZhCL4dze8su1w6pLN/pD1pGHtKYCEVbdTmaM3PblNRFf12XB7qosmQsgUndH4Vq3bTbU0s1pKjeDhRyLvFzvR0TBbo0pDLEoF1A/i5GVFWa7yLZNUDudQERRh7qv/xBl2excIaQ1sV4DSVm7bAE9l6Kp+yeHQJW2uN6Y3X8wu9gB9nv9l5HBze7wh8KE6PyWAOLYYqZg9/sAtsv/2GcQqXcKFF1zcA= diff --git a/vendor/github.com/go-openapi/validate/README.md b/vendor/github.com/go-openapi/validate/README.md index 7e7831c9ea4..e3bfc622be2 100644 --- a/vendor/github.com/go-openapi/validate/README.md +++ b/vendor/github.com/go-openapi/validate/README.md @@ -1,3 +1,3 @@ -# Validation helpers [![Build Status](https://ci.vmware.run/api/badges/go-openapi/validate/status.svg)](https://ci.vmware.run/go-openapi/validate) [![Coverage](https://coverage.vmware.run/badges/go-openapi/validate/coverage.svg)](https://coverage.vmware.run/go-openapi/validate) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) +# Validation helpers [![Build Status](https://travis-ci.org/go-openapi/validate.svg?branch=master)](https://travis-ci.org/go-openapi/validate) [![codecov](https://codecov.io/gh/go-openapi/validate/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/validate) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) [![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/validate/master/LICENSE) [![GoDoc](https://godoc.org/github.com/go-openapi/validate?status.svg)](http://godoc.org/github.com/go-openapi/validate) diff --git a/vendor/github.com/go-openapi/validate/formats.go b/vendor/github.com/go-openapi/validate/formats.go index f0e9f9039a1..294845aff38 100644 --- a/vendor/github.com/go-openapi/validate/formats.go +++ b/vendor/github.com/go-openapi/validate/formats.go @@ -15,6 +15,7 @@ package validate import ( + "log" "reflect" "github.com/go-openapi/spec" @@ -51,7 +52,9 @@ func (f *formatValidator) Applies(source interface{}, kind reflect.Kind) bool { return false } r := doit() - // fmt.Printf("schema props validator for %q applies %t for %T (kind: %v)\n", f.Path, r, source, kind) + if Debug { + log.Printf("format validator for %q applies %t for %T (kind: %v)\n", f.Path, r, source, kind) + } return r } diff --git a/vendor/github.com/go-openapi/validate/object_validator.go b/vendor/github.com/go-openapi/validate/object_validator.go index 7caff230c51..0dd580288df 100644 --- a/vendor/github.com/go-openapi/validate/object_validator.go +++ b/vendor/github.com/go-openapi/validate/object_validator.go @@ -15,8 +15,10 @@ package validate import ( + "log" "reflect" "regexp" + "strings" "github.com/go-openapi/errors" "github.com/go-openapi/spec" @@ -45,10 +47,45 @@ func (o *objectValidator) Applies(source interface{}, kind reflect.Kind) bool { // there is a problem in the type validator where it will be unhappy about null values // so that requires more testing r := reflect.TypeOf(source) == specSchemaType && (kind == reflect.Map || kind == reflect.Struct) - //fmt.Printf("object validator for %q applies %t for %T (kind: %v)\n", o.Path, r, source, kind) + if Debug { + log.Printf("object validator for %q applies %t for %T (kind: %v)\n", o.Path, r, source, kind) + } return r } +func (o *objectValidator) isPropertyName() bool { + p := strings.Split(o.Path, ".") + return p[len(p)-1] == "properties" && p[len(p)-2] != "properties" +} +func (o *objectValidator) checkArrayMustHaveItems(res *Result, val map[string]interface{}) { + if t, typeFound := val["type"]; typeFound { + if tpe, ok := t.(string); ok && tpe == "array" { + if _, itemsKeyFound := val["items"]; !itemsKeyFound { + res.AddErrors(errors.Required("items", o.Path)) + } + } + } +} + +func (o *objectValidator) checkItemsMustBeTypeArray(res *Result, val map[string]interface{}) { + if !o.isPropertyName() { + if _, itemsKeyFound := val["items"]; itemsKeyFound { + t, typeFound := val["type"] + if typeFound { + if tpe, ok := t.(string); !ok || tpe != "array" { + res.AddErrors(errors.InvalidType(o.Path, o.In, "array", nil)) + } + } else { + // there is no type + res.AddErrors(errors.Required("type", o.Path)) + } + } + } +} +func (o *objectValidator) precheck(res *Result, val map[string]interface{}) { + o.checkArrayMustHaveItems(res, val) + o.checkItemsMustBeTypeArray(res, val) +} func (o *objectValidator) Validate(data interface{}) *Result { val := data.(map[string]interface{}) numKeys := int64(len(val)) @@ -61,14 +98,8 @@ func (o *objectValidator) Validate(data interface{}) *Result { } res := new(Result) - if len(o.Required) > 0 { - for _, k := range o.Required { - if _, ok := val[k]; !ok { - res.AddErrors(errors.Required(o.Path+"."+k, o.In)) - continue - } - } - } + + o.precheck(res, val) if o.AdditionalProperties != nil && !o.AdditionalProperties.Allows { for k := range val { @@ -99,6 +130,8 @@ func (o *objectValidator) Validate(data interface{}) *Result { } } + createdFromDefaults := map[string]bool{} + for pName, pSchema := range o.Properties { rName := pName if o.Path != "" { @@ -106,7 +139,24 @@ func (o *objectValidator) Validate(data interface{}) *Result { } if v, ok := val[pName]; ok { - res.Merge(NewSchemaValidator(&pSchema, o.Root, rName, o.KnownFormats).Validate(v)) + r := NewSchemaValidator(&pSchema, o.Root, rName, o.KnownFormats).Validate(v) + res.Merge(r) + } else if pSchema.Default != nil { + createdFromDefaults[pName] = true + pName := pName // shaddow + def := pSchema.Default + res.Defaulters = append(res.Defaulters, DefaulterFunc(func() { + val[pName] = def + })) + } + } + + if len(o.Required) > 0 { + for _, k := range o.Required { + if _, ok := val[k]; !ok && !createdFromDefaults[k] { + res.AddErrors(errors.Required(o.Path+"."+k, o.In)) + continue + } } } @@ -137,9 +187,6 @@ func (o *objectValidator) validatePatternProperty(key string, value interface{}, res := validator.Validate(value) result.Merge(res) - if res.IsValid() { - succeededOnce = true - } } } diff --git a/vendor/github.com/go-openapi/validate/result.go b/vendor/github.com/go-openapi/validate/result.go index d8f71e9468b..7b58e50df71 100644 --- a/vendor/github.com/go-openapi/validate/result.go +++ b/vendor/github.com/go-openapi/validate/result.go @@ -14,12 +14,32 @@ package validate -import "github.com/go-openapi/errors" +import ( + "os" + + "github.com/go-openapi/errors" +) + +var ( + // Debug is true when the SWAGGER_DEBUG env var is not empty + Debug = os.Getenv("SWAGGER_DEBUG") != "" +) + +type Defaulter interface { + Apply() +} + +type DefaulterFunc func() + +func (f DefaulterFunc) Apply() { + f() +} // Result represents a validation result type Result struct { Errors []error MatchCount int + Defaulters []Defaulter } // Merge merges this result with the other one, preserving match counts etc @@ -29,11 +49,13 @@ func (r *Result) Merge(other *Result) *Result { } r.AddErrors(other.Errors...) r.MatchCount += other.MatchCount + r.Defaulters = append(r.Defaulters, other.Defaulters...) return r } // AddErrors adds errors to this validation result func (r *Result) AddErrors(errors ...error) { + // TODO: filter already existing errors r.Errors = append(r.Errors, errors...) } @@ -59,3 +81,9 @@ func (r *Result) AsError() error { } return errors.CompositeValidationError(r.Errors...) } + +func (r *Result) ApplyDefaults() { + for _, d := range r.Defaulters { + d.Apply() + } +} diff --git a/vendor/github.com/go-openapi/validate/schema.go b/vendor/github.com/go-openapi/validate/schema.go index 8bf7d3bcc9b..f859c6d6309 100644 --- a/vendor/github.com/go-openapi/validate/schema.go +++ b/vendor/github.com/go-openapi/validate/schema.go @@ -15,6 +15,8 @@ package validate import ( + "encoding/json" + "log" "reflect" "github.com/go-openapi/spec" @@ -80,12 +82,16 @@ func (s *SchemaValidator) Applies(source interface{}, kind reflect.Kind) bool { // Validate validates the data against the schema func (s *SchemaValidator) Validate(data interface{}) *Result { + result := new(Result) + if s == nil { + return result + } + if data == nil { v := s.validators[0].Validate(data) v.Merge(s.validators[6].Validate(data)) return v } - result := new(Result) tpe := reflect.TypeOf(data) kind := tpe.Kind() @@ -98,8 +104,35 @@ func (s *SchemaValidator) Validate(data interface{}) *Result { d = swag.ToDynamicJSON(data) } + isnumber := s.Schema.Type.Contains("number") || s.Schema.Type.Contains("integer") + if num, ok := data.(json.Number); ok && isnumber { + if s.Schema.Type.Contains("integer") { // avoid lossy conversion + in, erri := num.Int64() + if erri != nil { + result.AddErrors(erri) + result.Inc() + return result + } + d = in + } else { + nf, errf := num.Float64() + if errf != nil { + result.AddErrors(errf) + result.Inc() + return result + } + d = nf + } + + tpe = reflect.TypeOf(d) + kind = tpe.Kind() + } + for _, v := range s.validators { if !v.Applies(s.Schema, kind) { + if Debug { + log.Printf("%T does not apply for %v", v, kind) + } continue } @@ -117,10 +150,9 @@ func (s *SchemaValidator) typeValidator() valueValidator { func (s *SchemaValidator) commonValidator() valueValidator { return &basicCommonValidator{ - Path: s.Path, - In: s.in, - Default: s.Schema.Default, - Enum: s.Schema.Enum, + Path: s.Path, + In: s.in, + Enum: s.Schema.Enum, } } @@ -155,7 +187,6 @@ func (s *SchemaValidator) stringValidator() valueValidator { return &stringValidator{ Path: s.Path, In: s.in, - Default: s.Schema.Default, MaxLength: s.Schema.MaxLength, MinLength: s.Schema.MinLength, Pattern: s.Schema.Pattern, @@ -164,9 +195,8 @@ func (s *SchemaValidator) stringValidator() valueValidator { func (s *SchemaValidator) formatValidator() valueValidator { return &formatValidator{ - Path: s.Path, - In: s.in, - //Default: s.Schema.Default, + Path: s.Path, + In: s.in, Format: s.Schema.Format, KnownFormats: s.KnownFormats, } diff --git a/vendor/github.com/go-openapi/validate/schema_props.go b/vendor/github.com/go-openapi/validate/schema_props.go index feff6d6a37a..5d8ed404521 100644 --- a/vendor/github.com/go-openapi/validate/schema_props.go +++ b/vendor/github.com/go-openapi/validate/schema_props.go @@ -15,6 +15,7 @@ package validate import ( + "log" "reflect" "github.com/go-openapi/errors" @@ -80,12 +81,15 @@ func newSchemaPropsValidator(path string, in string, allOf, oneOf, anyOf []spec. func (s *schemaPropsValidator) Applies(source interface{}, kind reflect.Kind) bool { r := reflect.TypeOf(source) == specSchemaType - // fmt.Printf("schema props validator for %q applies %t for %T (kind: %v)\n", s.Path, r, source, kind) + if Debug { + log.Printf("schema props validator for %q applies %t for %T (kind: %v)\n", s.Path, r, source, kind) + } return r } func (s *schemaPropsValidator) Validate(data interface{}) *Result { mainResult := new(Result) + var firstSuccess *Result if len(s.anyOfValidators) > 0 { var bestFailures *Result succeededOnce := false @@ -94,6 +98,9 @@ func (s *schemaPropsValidator) Validate(data interface{}) *Result { if result.IsValid() { bestFailures = nil succeededOnce = true + if firstSuccess == nil { + firstSuccess = result + } break } if bestFailures == nil || result.MatchCount > bestFailures.MatchCount { @@ -106,11 +113,14 @@ func (s *schemaPropsValidator) Validate(data interface{}) *Result { } if bestFailures != nil { mainResult.Merge(bestFailures) + } else if firstSuccess != nil { + mainResult.Merge(firstSuccess) } } if len(s.oneOfValidators) > 0 { var bestFailures *Result + var firstSuccess *Result validated := 0 for _, oneOfSchema := range s.oneOfValidators { @@ -118,6 +128,9 @@ func (s *schemaPropsValidator) Validate(data interface{}) *Result { if result.IsValid() { validated++ bestFailures = nil + if firstSuccess == nil { + firstSuccess = result + } continue } if validated == 0 && (bestFailures == nil || result.MatchCount > bestFailures.MatchCount) { @@ -130,6 +143,8 @@ func (s *schemaPropsValidator) Validate(data interface{}) *Result { if bestFailures != nil { mainResult.Merge(bestFailures) } + } else if firstSuccess != nil { + mainResult.Merge(firstSuccess) } } diff --git a/vendor/github.com/go-openapi/validate/slice_validator.go b/vendor/github.com/go-openapi/validate/slice_validator.go index 8371061535d..2665a0ffe99 100644 --- a/vendor/github.com/go-openapi/validate/slice_validator.go +++ b/vendor/github.com/go-openapi/validate/slice_validator.go @@ -67,6 +67,9 @@ func (s *schemaSliceValidator) Validate(data interface{}) *Result { itemsSize = int64(len(s.Items.Schemas)) for i := int64(0); i < itemsSize; i++ { validator := NewSchemaValidator(&s.Items.Schemas[i], s.Root, fmt.Sprintf("%s.%d", s.Path, i), s.KnownFormats) + if val.Len() <= int(i) { + break + } result.Merge(validator.Validate(val.Index(int(i)).Interface())) } diff --git a/vendor/github.com/go-openapi/validate/spec.go b/vendor/github.com/go-openapi/validate/spec.go index 938bc5bf907..2f1d7028695 100644 --- a/vendor/github.com/go-openapi/validate/spec.go +++ b/vendor/github.com/go-openapi/validate/spec.go @@ -19,6 +19,7 @@ import ( "fmt" "log" "regexp" + "strconv" "strings" "github.com/go-openapi/analysis" @@ -193,6 +194,13 @@ func (s *SpecValidator) validateDuplicatePropertyNames() *Result { return res } +func (s *SpecValidator) resolveRef(ref *spec.Ref) (*spec.Schema, error) { + if s.spec.SpecFilePath() != "" { + return spec.ResolveRefWithBase(s.spec.Spec(), ref, &spec.ExpandOptions{RelativeBase: s.spec.SpecFilePath()}) + } + return spec.ResolveRef(s.spec.Spec(), ref) +} + func (s *SpecValidator) validateSchemaPropertyNames(nm string, sch spec.Schema, knowns map[string]struct{}) []dupProp { var dups []dupProp @@ -200,7 +208,7 @@ func (s *SpecValidator) validateSchemaPropertyNames(nm string, sch spec.Schema, schc := &sch for schc.Ref.String() != "" { // gather property names - reso, err := spec.ResolveRef(s.spec.Spec(), &schc.Ref) + reso, err := s.resolveRef(&schc.Ref) if err != nil { panic(err) } @@ -236,7 +244,7 @@ func (s *SpecValidator) validateCircularAncestry(nm string, sch spec.Schema, kno schn := nm schc := &sch for schc.Ref.String() != "" { - reso, err := spec.ResolveRef(s.spec.Spec(), &schc.Ref) + reso, err := s.resolveRef(&schc.Ref) if err != nil { panic(err) } @@ -335,15 +343,15 @@ func (s *SpecValidator) validateSchemaItems(schema spec.Schema, prefix, opID str return errors.New(422, "%s for %q is a collection without an element type", prefix, opID) } - schemas := schema.Items.Schemas if schema.Items.Schema != nil { - schemas = []spec.Schema{*schema.Items.Schema} - } - for _, sch := range schemas { - if err := s.validateSchemaItems(sch, prefix, opID); err != nil { - return err + schema = *schema.Items.Schema + if _, err := regexp.Compile(schema.Pattern); err != nil { + return errors.New(422, "%s for %q has invalid items pattern: %q", prefix, opID, schema.Pattern) } + + return s.validateSchemaItems(schema, prefix, opID) } + return nil } @@ -524,8 +532,15 @@ func (s *SpecValidator) validateParameters() *Result { } var fromPath []string for _, i := range params { - fromPath = append(fromPath, knowns[i]) - knowns[i] = "!" + knownsi := knowns[i] + iparams := extractPathParams(knownsi) + if len(iparams) > 0 { + fromPath = append(fromPath, iparams...) + for _, iparam := range iparams { + knownsi = strings.Replace(knownsi, iparam, "!", 1) + } + knowns[i] = knownsi + } } knownPath := strings.Join(knowns, "/") if orig, ok := knownPaths[knownPath]; ok { @@ -544,7 +559,9 @@ func (s *SpecValidator) validateParameters() *Result { for pr.Ref.String() != "" { obj, _, err := pr.Ref.GetPointer().Get(sw) if err != nil { - log.Println(err) + if Debug { + log.Println(err) + } res.AddErrors(err) break PARAMETERS } @@ -575,6 +592,10 @@ func (s *SpecValidator) validateParameters() *Result { pr = obj.(spec.Parameter) } + if _, err := regexp.Compile(pr.Pattern); err != nil { + res.AddErrors(errors.New(422, "operation %q has invalid pattern in param %q: %q", op.ID, pr.Name, pr.Pattern)) + } + if pr.In == "body" { if firstBodyParam != "" { res.AddErrors(errors.New(422, "operation %q has more than 1 body param (accepted: %q, dropped: %q)", op.ID, firstBodyParam, pr.Name)) @@ -595,18 +616,35 @@ func (s *SpecValidator) validateParameters() *Result { func parsePath(path string) (segments []string, params []int) { for i, p := range strings.Split(path, "/") { segments = append(segments, p) - if len(p) > 0 && p[0] == '{' && p[len(p)-1] == '}' { + if d0 := strings.Index(p, "{"); d0 >= 0 && d0 < strings.Index(p, "}") { params = append(params, i) } } return } +func extractPathParams(segment string) (params []string) { + for { + d0 := strings.IndexByte(segment, '{') + if d0 < 0 { + break + } + d1 := strings.IndexByte(segment[d0:], '}') + if d1 > 0 { + params = append(params, segment[d0:d0+d1+1]) + } else { + break + } + segment = segment[d1:] + } + return params +} + func (s *SpecValidator) validateReferencesValid() *Result { // each reference must point to a valid object res := new(Result) for _, r := range s.analyzer.AllRefs() { - if !r.IsValidURI() { + if !r.IsValidURI(s.spec.SpecFilePath()) { res.AddErrors(errors.New(404, "invalid ref %q", r.String())) } } @@ -698,7 +736,9 @@ func (s *SpecValidator) validateDefaultValueValidAgainstSchema() *Result { } // check simple paramters first if param.Default != nil && param.Schema == nil { - //fmt.Println(param.Name, "in", param.In, "has a default without a schema") + if Debug { + log.Println(param.Name, "in", param.In, "has a default without a schema") + } // check param valid res.Merge(NewParamValidator(¶m, s.KnownFormats).Validate(param.Default)) } @@ -721,9 +761,15 @@ func (s *SpecValidator) validateDefaultValueValidAgainstSchema() *Result { if h.Items != nil { res.Merge(s.validateDefaultValueItemsAgainstSchema(nm, "header", &h, h.Items)) } + if _, err := regexp.Compile(h.Pattern); err != nil { + res.AddErrors(errors.New(422, "operation %q has invalid pattern in default header %q: %q", op.ID, nm, h.Pattern)) + } + } + if dr.Schema != nil { + res.Merge(s.validateDefaultValueSchemaAgainstSchema("default", "response", dr.Schema)) } } - for _, r := range op.Responses.StatusCodeResponses { + for code, r := range op.Responses.StatusCodeResponses { for nm, h := range r.Headers { if h.Default != nil { res.Merge(NewHeaderValidator(nm, &h, s.KnownFormats).Validate(h.Default)) @@ -731,6 +777,12 @@ func (s *SpecValidator) validateDefaultValueValidAgainstSchema() *Result { if h.Items != nil { res.Merge(s.validateDefaultValueItemsAgainstSchema(nm, "header", &h, h.Items)) } + if _, err := regexp.Compile(h.Pattern); err != nil { + res.AddErrors(errors.New(422, "operation %q has invalid pattern in %v's header %q: %q", op.ID, code, nm, h.Pattern)) + } + } + if r.Schema != nil { + res.Merge(s.validateDefaultValueSchemaAgainstSchema(strconv.Itoa(code), "response", r.Schema)) } } @@ -758,6 +810,9 @@ func (s *SpecValidator) validateDefaultValueSchemaAgainstSchema(path, in string, res.Merge(s.validateDefaultValueSchemaAgainstSchema(fmt.Sprintf("%s.items[%d]", path, i), in, &sch)) } } + if _, err := regexp.Compile(schema.Pattern); err != nil { + res.AddErrors(errors.New(422, "%s in %s has invalid pattern: %q", path, in, schema.Pattern)) + } if schema.AdditionalItems != nil && schema.AdditionalItems.Schema != nil { res.Merge(s.validateDefaultValueSchemaAgainstSchema(fmt.Sprintf("%s.additionalItems", path), in, schema.AdditionalItems.Schema)) } @@ -787,6 +842,9 @@ func (s *SpecValidator) validateDefaultValueItemsAgainstSchema(path, in string, if items.Items != nil { res.Merge(s.validateDefaultValueItemsAgainstSchema(path+"[0]", in, root, items.Items)) } + if _, err := regexp.Compile(items.Pattern); err != nil { + res.AddErrors(errors.New(422, "%s in %s has invalid pattern: %q", path, in, items.Pattern)) + } } return res } diff --git a/vendor/github.com/go-openapi/validate/type.go b/vendor/github.com/go-openapi/validate/type.go index 0a5f4a2932a..3ae31f087a5 100644 --- a/vendor/github.com/go-openapi/validate/type.go +++ b/vendor/github.com/go-openapi/validate/type.go @@ -15,6 +15,7 @@ package validate import ( + "log" "reflect" "strings" @@ -32,16 +33,6 @@ type typeValidator struct { Path string } -var jsonTypeNames = map[string]struct{}{ - "array": struct{}{}, - "boolean": struct{}{}, - "integer": struct{}{}, - "null": struct{}{}, - "number": struct{}{}, - "object": struct{}{}, - "string": struct{}{}, -} - func (t *typeValidator) schemaInfoForType(data interface{}) (string, string) { switch data.(type) { case []byte: @@ -121,7 +112,9 @@ func (t *typeValidator) SetPath(path string) { func (t *typeValidator) Applies(source interface{}, kind reflect.Kind) bool { stpe := reflect.TypeOf(source) r := (len(t.Type) > 0 || t.Format != "") && (stpe == specSchemaType || stpe == specParameterType || stpe == specHeaderType) - //fmt.Printf("type validator for %q applies %t for %T (kind: %v)\n", t.Path, r, source, kind) + if Debug { + log.Printf("type validator for %q applies %t for %T (kind: %v)\n", t.Path, r, source, kind) + } return r } @@ -140,7 +133,9 @@ func (t *typeValidator) Validate(data interface{}) *Result { kind := val.Kind() schType, format := t.schemaInfoForType(data) - //fmt.Println("path:", t.Path, "schType:", schType, "format:", format, "expType:", t.Type, "expFmt:", t.Format, "kind:", val.Kind().String()) + if Debug { + log.Println("path:", t.Path, "schType:", schType, "format:", format, "expType:", t.Type, "expFmt:", t.Format, "kind:", val.Kind().String()) + } isLowerInt := t.Format == "int64" && format == "int32" isLowerFloat := t.Format == "float64" && format == "float32" isFloatInt := schType == "number" && swag.IsFloat64AJSONInteger(val.Float()) && t.Type.Contains("integer") diff --git a/vendor/github.com/go-openapi/validate/update-fixtures.sh b/vendor/github.com/go-openapi/validate/update-fixtures.sh new file mode 100755 index 00000000000..21b06e2b09a --- /dev/null +++ b/vendor/github.com/go-openapi/validate/update-fixtures.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +set -eu -o pipefail +dir=$(git rev-parse --show-toplevel) +scratch=$(mktemp -d -t tmp.XXXXXXXXXX) + +function finish { + rm -rf "$scratch" +} +trap finish EXIT SIGHUP SIGINT SIGTERM + +cd "$scratch" +git clone https://github.com/json-schema-org/JSON-Schema-Test-Suite Suite +cp -r Suite/tests/draft4/* "$dir/fixtures/jsonschema_suite" +cp -a Suite/remotes "$dir/fixtures/jsonschema_suite" diff --git a/vendor/github.com/go-openapi/validate/validator.go b/vendor/github.com/go-openapi/validate/validator.go index 45675d28f31..64a379fcde1 100644 --- a/vendor/github.com/go-openapi/validate/validator.go +++ b/vendor/github.com/go-openapi/validate/validator.go @@ -16,6 +16,7 @@ package validate import ( "fmt" + "log" "reflect" "github.com/go-openapi/errors" @@ -156,8 +157,15 @@ func (b *basicCommonValidator) Applies(source interface{}, kind reflect.Kind) bo func (b *basicCommonValidator) Validate(data interface{}) (res *Result) { if len(b.Enum) > 0 { for _, enumValue := range b.Enum { - if data != nil && reflect.DeepEqual(enumValue, data) { - return nil + actualType := reflect.TypeOf(enumValue) + if actualType == nil { + continue + } + expectedValue := reflect.ValueOf(data) + if expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) { + if reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), enumValue) { + return nil + } } } return sErr(errors.EnumFail(b.Path, b.In, data, b.Enum)) @@ -474,10 +482,14 @@ func (n *numberValidator) Applies(source interface{}, kind reflect.Kind) bool { isInt := kind >= reflect.Int && kind <= reflect.Uint64 isFloat := kind == reflect.Float32 || kind == reflect.Float64 r := isInt || isFloat - // fmt.Printf("schema props validator for %q applies %t for %T (kind: %v)\n", n.Path, r, source, kind) + if Debug { + log.Printf("schema props validator for %q applies %t for %T (kind: %v)\n", n.Path, r, source, kind) + } return r } - // fmt.Printf("schema props validator for %q applies %t for %T (kind: %v)\n", n.Path, false, source, kind) + if Debug { + log.Printf("schema props validator for %q applies %t for %T (kind: %v)\n", n.Path, false, source, kind) + } return false } @@ -536,15 +548,22 @@ func (s *stringValidator) Applies(source interface{}, kind reflect.Kind) bool { switch source.(type) { case *spec.Parameter, *spec.Schema, *spec.Items, *spec.Header: r := kind == reflect.String - // fmt.Printf("string validator for %q applies %t for %T (kind: %v)\n", s.Path, r, source, kind) + if Debug { + log.Printf("string validator for %q applies %t for %T (kind: %v)\n", s.Path, r, source, kind) + } return r } - // fmt.Printf("string validator for %q applies %t for %T (kind: %v)\n", s.Path, false, source, kind) + if Debug { + log.Printf("string validator for %q applies %t for %T (kind: %v)\n", s.Path, false, source, kind) + } return false } func (s *stringValidator) Validate(val interface{}) *Result { - data := val.(string) + data, ok := val.(string) + if !ok { + return sErr(errors.InvalidType(s.Path, s.In, "string", val)) + } if s.Required && !s.AllowEmptyValue && (s.Default == nil || s.Default == "") { if err := RequiredString(s.Path, s.In, data); err != nil { diff --git a/vendor/github.com/go-openapi/validate/values.go b/vendor/github.com/go-openapi/validate/values.go index ab5ce8af508..67895d1ec60 100644 --- a/vendor/github.com/go-openapi/validate/values.go +++ b/vendor/github.com/go-openapi/validate/values.go @@ -196,7 +196,11 @@ func MinimumUint(path, in string, data, min uint64, exclusive bool) *errors.Vali // MultipleOf validates if the provided number is a multiple of the factor func MultipleOf(path, in string, data, factor float64) *errors.Validation { - if !swag.IsFloat64AJSONInteger(data / factor) { + mult := data / factor + if factor < 1 { + mult = 1 / factor * data + } + if !swag.IsFloat64AJSONInteger(mult) { return errors.NotMultipleOf(path, in, factor) } return nil