mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-10-31 18:28:13 +00:00 
			
		
		
		
	 f622dd918a
			
		
	
	f622dd918a
	
	
	
		
			
			hack/pin-dependency.sh k8s.io/kube-openapi 172d655c2280350c77cf05962948fc67ff043492 hack/update-vendor.sh
		
			
				
	
	
		
			503 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			503 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| /*
 | |
| Copyright 2022 The Kubernetes Authors.
 | |
| 
 | |
| Licensed under the Apache License, Version 2.0 (the "License");
 | |
| you may not use this file except in compliance with the License.
 | |
| You may obtain a copy of the License at
 | |
| 
 | |
| 	http://www.apache.org/licenses/LICENSE-2.0
 | |
| 
 | |
| Unless required by applicable law or agreed to in writing, software
 | |
| distributed under the License is distributed on an "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| See the License for the specific language governing permissions and
 | |
| limitations under the License.
 | |
| */
 | |
| 
 | |
| package spec
 | |
| 
 | |
| import (
 | |
| 	"github.com/go-openapi/jsonreference"
 | |
| 	"github.com/google/go-cmp/cmp"
 | |
| 	fuzz "github.com/google/gofuzz"
 | |
| )
 | |
| 
 | |
| var SwaggerFuzzFuncs []interface{} = []interface{}{
 | |
| 	func(v *Responses, c fuzz.Continue) {
 | |
| 		c.FuzzNoCustom(v)
 | |
| 		if v.Default != nil {
 | |
| 			// Check if we hit maxDepth and left an incomplete value
 | |
| 			if v.Default.Description == "" {
 | |
| 				v.Default = nil
 | |
| 				v.StatusCodeResponses = nil
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		// conversion has no way to discern empty statusCodeResponses from
 | |
| 		// nil, since "default" is always included in the map.
 | |
| 		// So avoid empty responses list
 | |
| 		if len(v.StatusCodeResponses) == 0 {
 | |
| 			v.StatusCodeResponses = nil
 | |
| 		}
 | |
| 	},
 | |
| 	func(v *Operation, c fuzz.Continue) {
 | |
| 		c.FuzzNoCustom(v)
 | |
| 
 | |
| 		if v != nil {
 | |
| 			// force non-nil
 | |
| 			v.Responses = &Responses{}
 | |
| 			c.Fuzz(v.Responses)
 | |
| 
 | |
| 			v.Schemes = nil
 | |
| 			if c.RandBool() {
 | |
| 				v.Schemes = append(v.Schemes, "http")
 | |
| 			}
 | |
| 
 | |
| 			if c.RandBool() {
 | |
| 				v.Schemes = append(v.Schemes, "https")
 | |
| 			}
 | |
| 
 | |
| 			if c.RandBool() {
 | |
| 				v.Schemes = append(v.Schemes, "ws")
 | |
| 			}
 | |
| 
 | |
| 			if c.RandBool() {
 | |
| 				v.Schemes = append(v.Schemes, "wss")
 | |
| 			}
 | |
| 
 | |
| 			// Gnostic unconditionally makes security values non-null
 | |
| 			// So do not fuzz null values into the array.
 | |
| 			for i, val := range v.Security {
 | |
| 				if val == nil {
 | |
| 					v.Security[i] = make(map[string][]string)
 | |
| 				}
 | |
| 
 | |
| 				for k, v := range val {
 | |
| 					if v == nil {
 | |
| 						val[k] = make([]string, 0)
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	},
 | |
| 	func(v map[int]Response, c fuzz.Continue) {
 | |
| 		n := 0
 | |
| 		c.Fuzz(&n)
 | |
| 		if n == 0 {
 | |
| 			// Test that fuzzer is not at maxDepth so we do not
 | |
| 			// end up with empty elements
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		// Prevent negative numbers
 | |
| 		num := c.Intn(4)
 | |
| 		for i := 0; i < num+2; i++ {
 | |
| 			val := Response{}
 | |
| 			c.Fuzz(&val)
 | |
| 
 | |
| 			val.Description = c.RandString() + "x"
 | |
| 			v[100*(i+1)+c.Intn(100)] = val
 | |
| 		}
 | |
| 	},
 | |
| 	func(v map[string]PathItem, c fuzz.Continue) {
 | |
| 		n := 0
 | |
| 		c.Fuzz(&n)
 | |
| 		if n == 0 {
 | |
| 			// Test that fuzzer is not at maxDepth so we do not
 | |
| 			// end up with empty elements
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		num := c.Intn(5)
 | |
| 		for i := 0; i < num+2; i++ {
 | |
| 			val := PathItem{}
 | |
| 			c.Fuzz(&val)
 | |
| 
 | |
| 			// Ref params are only allowed in certain locations, so
 | |
| 			// possibly add a few to PathItems
 | |
| 			numRefsToAdd := c.Intn(5)
 | |
| 			for i := 0; i < numRefsToAdd; i++ {
 | |
| 				theRef := Parameter{}
 | |
| 				c.Fuzz(&theRef.Refable)
 | |
| 
 | |
| 				val.Parameters = append(val.Parameters, theRef)
 | |
| 			}
 | |
| 
 | |
| 			v["/"+c.RandString()] = val
 | |
| 		}
 | |
| 	},
 | |
| 	func(v *SchemaOrArray, c fuzz.Continue) {
 | |
| 		*v = SchemaOrArray{}
 | |
| 		// gnostic parser just doesn't support more
 | |
| 		// than one Schema here
 | |
| 		v.Schema = &Schema{}
 | |
| 		c.Fuzz(&v.Schema)
 | |
| 
 | |
| 	},
 | |
| 	func(v *SchemaOrBool, c fuzz.Continue) {
 | |
| 		*v = SchemaOrBool{}
 | |
| 
 | |
| 		if c.RandBool() {
 | |
| 			v.Allows = c.RandBool()
 | |
| 		} else {
 | |
| 			v.Schema = &Schema{}
 | |
| 			v.Allows = true
 | |
| 			c.Fuzz(&v.Schema)
 | |
| 		}
 | |
| 	},
 | |
| 	func(v map[string]Response, c fuzz.Continue) {
 | |
| 		n := 0
 | |
| 		c.Fuzz(&n)
 | |
| 		if n == 0 {
 | |
| 			// Test that fuzzer is not at maxDepth so we do not
 | |
| 			// end up with empty elements
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		// Response definitions are not allowed to
 | |
| 		// be refs
 | |
| 		for i := 0; i < c.Intn(5)+1; i++ {
 | |
| 			resp := &Response{}
 | |
| 
 | |
| 			c.Fuzz(resp)
 | |
| 			resp.Ref = Ref{}
 | |
| 			resp.Description = c.RandString() + "x"
 | |
| 
 | |
| 			// Response refs are not vendor extensible by gnostic
 | |
| 			resp.VendorExtensible.Extensions = nil
 | |
| 			v[c.RandString()+"x"] = *resp
 | |
| 		}
 | |
| 	},
 | |
| 	func(v *Header, c fuzz.Continue) {
 | |
| 		if v != nil {
 | |
| 			c.FuzzNoCustom(v)
 | |
| 
 | |
| 			// descendant Items of Header may not be refs
 | |
| 			cur := v.Items
 | |
| 			for cur != nil {
 | |
| 				cur.Ref = Ref{}
 | |
| 				cur = cur.Items
 | |
| 			}
 | |
| 		}
 | |
| 	},
 | |
| 	func(v *Ref, c fuzz.Continue) {
 | |
| 		*v = Ref{}
 | |
| 		v.Ref, _ = jsonreference.New("http://asd.com/" + c.RandString())
 | |
| 	},
 | |
| 	func(v *Response, c fuzz.Continue) {
 | |
| 		*v = Response{}
 | |
| 		if c.RandBool() {
 | |
| 			v.Ref = Ref{}
 | |
| 			v.Ref.Ref, _ = jsonreference.New("http://asd.com/" + c.RandString())
 | |
| 		} else {
 | |
| 			c.Fuzz(&v.VendorExtensible)
 | |
| 			c.Fuzz(&v.Schema)
 | |
| 			c.Fuzz(&v.ResponseProps)
 | |
| 
 | |
| 			v.Headers = nil
 | |
| 			v.Ref = Ref{}
 | |
| 
 | |
| 			n := 0
 | |
| 			c.Fuzz(&n)
 | |
| 			if n != 0 {
 | |
| 				// Test that fuzzer is not at maxDepth so we do not
 | |
| 				// end up with empty elements
 | |
| 				num := c.Intn(4)
 | |
| 				for i := 0; i < num; i++ {
 | |
| 					if v.Headers == nil {
 | |
| 						v.Headers = make(map[string]Header)
 | |
| 					}
 | |
| 					hdr := Header{}
 | |
| 					c.Fuzz(&hdr)
 | |
| 					if hdr.Type == "" {
 | |
| 						// hit maxDepth, just abort trying to make haders
 | |
| 						v.Headers = nil
 | |
| 						break
 | |
| 					}
 | |
| 					v.Headers[c.RandString()+"x"] = hdr
 | |
| 				}
 | |
| 			} else {
 | |
| 				v.Headers = nil
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		v.Description = c.RandString() + "x"
 | |
| 
 | |
| 		// Gnostic parses empty as nil, so to keep avoid putting empty
 | |
| 		if len(v.Headers) == 0 {
 | |
| 			v.Headers = nil
 | |
| 		}
 | |
| 	},
 | |
| 	func(v **Info, c fuzz.Continue) {
 | |
| 		// Info is never nil
 | |
| 		*v = &Info{}
 | |
| 		c.FuzzNoCustom(*v)
 | |
| 
 | |
| 		(*v).Title = c.RandString() + "x"
 | |
| 	},
 | |
| 	func(v *Extensions, c fuzz.Continue) {
 | |
| 		// gnostic parser only picks up x- vendor extensions
 | |
| 		numChildren := c.Intn(5)
 | |
| 		for i := 0; i < numChildren; i++ {
 | |
| 			if *v == nil {
 | |
| 				*v = Extensions{}
 | |
| 			}
 | |
| 			(*v)["x-"+c.RandString()] = c.RandString()
 | |
| 		}
 | |
| 	},
 | |
| 	func(v *Swagger, c fuzz.Continue) {
 | |
| 		c.FuzzNoCustom(v)
 | |
| 
 | |
| 		if v.Paths == nil {
 | |
| 			// Force paths non-nil since it does not have omitempty in json tag.
 | |
| 			// This means a perfect roundtrip (via json) is impossible,
 | |
| 			// since we can't tell the difference between empty/unspecified paths
 | |
| 			v.Paths = &Paths{}
 | |
| 			c.Fuzz(v.Paths)
 | |
| 		}
 | |
| 
 | |
| 		v.Swagger = "2.0"
 | |
| 
 | |
| 		// Gnostic support serializing ID at all
 | |
| 		// unavoidable data loss
 | |
| 		v.ID = ""
 | |
| 
 | |
| 		v.Schemes = nil
 | |
| 		if c.RandUint64()%2 == 1 {
 | |
| 			v.Schemes = append(v.Schemes, "http")
 | |
| 		}
 | |
| 
 | |
| 		if c.RandUint64()%2 == 1 {
 | |
| 			v.Schemes = append(v.Schemes, "https")
 | |
| 		}
 | |
| 
 | |
| 		if c.RandUint64()%2 == 1 {
 | |
| 			v.Schemes = append(v.Schemes, "ws")
 | |
| 		}
 | |
| 
 | |
| 		if c.RandUint64()%2 == 1 {
 | |
| 			v.Schemes = append(v.Schemes, "wss")
 | |
| 		}
 | |
| 
 | |
| 		// Gnostic unconditionally makes security values non-null
 | |
| 		// So do not fuzz null values into the array.
 | |
| 		for i, val := range v.Security {
 | |
| 			if val == nil {
 | |
| 				v.Security[i] = make(map[string][]string)
 | |
| 			}
 | |
| 
 | |
| 			for k, v := range val {
 | |
| 				if v == nil {
 | |
| 					val[k] = make([]string, 0)
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	},
 | |
| 	func(v *SecurityScheme, c fuzz.Continue) {
 | |
| 		v.Description = c.RandString() + "x"
 | |
| 		c.Fuzz(&v.VendorExtensible)
 | |
| 
 | |
| 		switch c.Intn(3) {
 | |
| 		case 0:
 | |
| 			v.Type = "basic"
 | |
| 		case 1:
 | |
| 			v.Type = "apiKey"
 | |
| 			switch c.Intn(2) {
 | |
| 			case 0:
 | |
| 				v.In = "header"
 | |
| 			case 1:
 | |
| 				v.In = "query"
 | |
| 			default:
 | |
| 				panic("unreachable")
 | |
| 			}
 | |
| 			v.Name = "x" + c.RandString()
 | |
| 		case 2:
 | |
| 			v.Type = "oauth2"
 | |
| 
 | |
| 			switch c.Intn(4) {
 | |
| 			case 0:
 | |
| 				v.Flow = "accessCode"
 | |
| 				v.TokenURL = "https://" + c.RandString()
 | |
| 				v.AuthorizationURL = "https://" + c.RandString()
 | |
| 			case 1:
 | |
| 				v.Flow = "application"
 | |
| 				v.TokenURL = "https://" + c.RandString()
 | |
| 			case 2:
 | |
| 				v.Flow = "implicit"
 | |
| 				v.AuthorizationURL = "https://" + c.RandString()
 | |
| 			case 3:
 | |
| 				v.Flow = "password"
 | |
| 				v.TokenURL = "https://" + c.RandString()
 | |
| 			default:
 | |
| 				panic("unreachable")
 | |
| 			}
 | |
| 			c.Fuzz(&v.Scopes)
 | |
| 		default:
 | |
| 			panic("unreachable")
 | |
| 		}
 | |
| 	},
 | |
| 	func(v *interface{}, c fuzz.Continue) {
 | |
| 		*v = c.RandString() + "x"
 | |
| 	},
 | |
| 	func(v *string, c fuzz.Continue) {
 | |
| 		*v = c.RandString() + "x"
 | |
| 	},
 | |
| 	func(v *ExternalDocumentation, c fuzz.Continue) {
 | |
| 		v.Description = c.RandString() + "x"
 | |
| 		v.URL = c.RandString() + "x"
 | |
| 	},
 | |
| 	func(v *SimpleSchema, c fuzz.Continue) {
 | |
| 		c.FuzzNoCustom(v)
 | |
| 
 | |
| 		switch c.Intn(5) {
 | |
| 		case 0:
 | |
| 			v.Type = "string"
 | |
| 		case 1:
 | |
| 			v.Type = "number"
 | |
| 		case 2:
 | |
| 			v.Type = "boolean"
 | |
| 		case 3:
 | |
| 			v.Type = "integer"
 | |
| 		case 4:
 | |
| 			v.Type = "array"
 | |
| 		default:
 | |
| 			panic("unreachable")
 | |
| 		}
 | |
| 
 | |
| 		switch c.Intn(5) {
 | |
| 		case 0:
 | |
| 			v.CollectionFormat = "csv"
 | |
| 		case 1:
 | |
| 			v.CollectionFormat = "ssv"
 | |
| 		case 2:
 | |
| 			v.CollectionFormat = "tsv"
 | |
| 		case 3:
 | |
| 			v.CollectionFormat = "pipes"
 | |
| 		case 4:
 | |
| 			v.CollectionFormat = ""
 | |
| 		default:
 | |
| 			panic("unreachable")
 | |
| 		}
 | |
| 
 | |
| 		// None of the types which include SimpleSchema in our definitions
 | |
| 		// actually support "example" in the official spec
 | |
| 		v.Example = nil
 | |
| 
 | |
| 		// unsupported by openapi
 | |
| 		v.Nullable = false
 | |
| 	},
 | |
| 	func(v *int64, c fuzz.Continue) {
 | |
| 		c.Fuzz(v)
 | |
| 
 | |
| 		// Gnostic does not differentiate between 0 and non-specified
 | |
| 		// so avoid using 0 for fuzzer
 | |
| 		if *v == 0 {
 | |
| 			*v = 1
 | |
| 		}
 | |
| 	},
 | |
| 	func(v *float64, c fuzz.Continue) {
 | |
| 		c.Fuzz(v)
 | |
| 
 | |
| 		// Gnostic does not differentiate between 0 and non-specified
 | |
| 		// so avoid using 0 for fuzzer
 | |
| 		if *v == 0.0 {
 | |
| 			*v = 1.0
 | |
| 		}
 | |
| 	},
 | |
| 	func(v *Parameter, c fuzz.Continue) {
 | |
| 		if v == nil {
 | |
| 			return
 | |
| 		}
 | |
| 		c.Fuzz(&v.VendorExtensible)
 | |
| 		if c.RandBool() {
 | |
| 			// body param
 | |
| 			v.Description = c.RandString() + "x"
 | |
| 			v.Name = c.RandString() + "x"
 | |
| 			v.In = "body"
 | |
| 			c.Fuzz(&v.Description)
 | |
| 			c.Fuzz(&v.Required)
 | |
| 
 | |
| 			v.Schema = &Schema{}
 | |
| 			c.Fuzz(&v.Schema)
 | |
| 
 | |
| 		} else {
 | |
| 			c.Fuzz(&v.SimpleSchema)
 | |
| 			c.Fuzz(&v.CommonValidations)
 | |
| 			v.AllowEmptyValue = false
 | |
| 			v.Description = c.RandString() + "x"
 | |
| 			v.Name = c.RandString() + "x"
 | |
| 
 | |
| 			switch c.Intn(4) {
 | |
| 			case 0:
 | |
| 				// Header param
 | |
| 				v.In = "header"
 | |
| 			case 1:
 | |
| 				// Form data param
 | |
| 				v.In = "formData"
 | |
| 				v.AllowEmptyValue = c.RandBool()
 | |
| 			case 2:
 | |
| 				// Query param
 | |
| 				v.In = "query"
 | |
| 				v.AllowEmptyValue = c.RandBool()
 | |
| 			case 3:
 | |
| 				// Path param
 | |
| 				v.In = "path"
 | |
| 				v.Required = true
 | |
| 			default:
 | |
| 				panic("unreachable")
 | |
| 			}
 | |
| 
 | |
| 			// descendant Items of Parameter may not be refs
 | |
| 			cur := v.Items
 | |
| 			for cur != nil {
 | |
| 				cur.Ref = Ref{}
 | |
| 				cur = cur.Items
 | |
| 			}
 | |
| 		}
 | |
| 	},
 | |
| 	func(v *Schema, c fuzz.Continue) {
 | |
| 		if c.RandBool() {
 | |
| 			// file schema
 | |
| 			c.Fuzz(&v.Default)
 | |
| 			c.Fuzz(&v.Description)
 | |
| 			c.Fuzz(&v.Example)
 | |
| 			c.Fuzz(&v.ExternalDocs)
 | |
| 
 | |
| 			c.Fuzz(&v.Format)
 | |
| 			c.Fuzz(&v.ReadOnly)
 | |
| 			c.Fuzz(&v.Required)
 | |
| 			c.Fuzz(&v.Title)
 | |
| 			v.Type = StringOrArray{"file"}
 | |
| 
 | |
| 		} else {
 | |
| 			// normal schema
 | |
| 			c.Fuzz(&v.SchemaProps)
 | |
| 			c.Fuzz(&v.SwaggerSchemaProps)
 | |
| 			c.Fuzz(&v.VendorExtensible)
 | |
| 			// c.Fuzz(&v.ExtraProps)
 | |
| 			// ExtraProps will not roundtrip - gnostic throws out
 | |
| 			// unrecognized keys
 | |
| 		}
 | |
| 
 | |
| 		// Not supported by official openapi v2 spec
 | |
| 		// and stripped by k8s apiserver
 | |
| 		v.ID = ""
 | |
| 		v.AnyOf = nil
 | |
| 		v.OneOf = nil
 | |
| 		v.Not = nil
 | |
| 		v.Nullable = false
 | |
| 		v.AdditionalItems = nil
 | |
| 		v.Schema = ""
 | |
| 		v.PatternProperties = nil
 | |
| 		v.Definitions = nil
 | |
| 		v.Dependencies = nil
 | |
| 	},
 | |
| }
 | |
| 
 | |
| var SwaggerDiffOptions = []cmp.Option{
 | |
| 	// cmp.Diff panics on Ref since jsonreference.Ref uses unexported fields
 | |
| 	cmp.Comparer(func(a Ref, b Ref) bool {
 | |
| 		return a.String() == b.String()
 | |
| 	}),
 | |
| }
 |