mirror of https://github.com/k3s-io/k3s
bump(go-openapi/validate): d509235108fcf6ab4913d2dcb3a2260c0db2108e
parent
2b530438f1
commit
66a4e5122a
|
@ -1263,7 +1263,7 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/validate",
|
||||
"Rev": "deaf2c9013bc1a7f4c774662259a506ba874d80f"
|
||||
"Rev": "d509235108fcf6ab4913d2dcb3a2260c0db2108e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/godbus/dbus",
|
||||
|
|
|
@ -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
|
|
@ -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"
|
|
@ -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
|
|
@ -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=
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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()))
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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"
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue