k8s.io/kube-openapi@v0.0.0-20240228011516-70dd3763d340/pkg/spec3/fuzz.go (about) 1 package spec3 2 3 import ( 4 "math/rand" 5 "strings" 6 7 fuzz "github.com/google/gofuzz" 8 9 "k8s.io/kube-openapi/pkg/validation/spec" 10 ) 11 12 // refChance is the chance that a particular component will use a $ref 13 // instead of fuzzed. Expressed as a fraction 1/n, currently there is 14 // a 1/3 chance that a ref will be used. 15 const refChance = 3 16 17 const alphaNumChars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 18 19 func randAlphanumString() string { 20 arr := make([]string, rand.Intn(10)+5) 21 for i := 0; i < len(arr); i++ { 22 arr[i] = string(alphaNumChars[rand.Intn(len(alphaNumChars))]) 23 } 24 return strings.Join(arr, "") 25 } 26 27 var OpenAPIV3FuzzFuncs []interface{} = []interface{}{ 28 func(s *string, c fuzz.Continue) { 29 // All OpenAPI V3 map keys must follow the corresponding 30 // regex. Note that this restricts the range for all other 31 // string values as well. 32 str := randAlphanumString() 33 *s = str 34 }, 35 func(o *OpenAPI, c fuzz.Continue) { 36 c.FuzzNoCustom(o) 37 o.Version = "3.0.0" 38 for i, val := range o.SecurityRequirement { 39 if val == nil { 40 o.SecurityRequirement[i] = make(map[string][]string) 41 } 42 43 for k, v := range val { 44 if v == nil { 45 val[k] = make([]string, 0) 46 } 47 } 48 } 49 50 }, 51 func(r *interface{}, c fuzz.Continue) { 52 switch c.Intn(3) { 53 case 0: 54 *r = nil 55 case 1: 56 n := c.RandString() + "x" 57 *r = n 58 case 2: 59 n := c.Float64() 60 *r = n 61 } 62 }, 63 func(v **spec.Info, c fuzz.Continue) { 64 // Info is never nil 65 *v = &spec.Info{} 66 c.FuzzNoCustom(*v) 67 (*v).Title = c.RandString() + "x" 68 }, 69 func(v *Paths, c fuzz.Continue) { 70 c.Fuzz(&v.VendorExtensible) 71 num := c.Intn(5) 72 if num > 0 { 73 v.Paths = make(map[string]*Path) 74 } 75 for i := 0; i < num; i++ { 76 val := Path{} 77 c.Fuzz(&val) 78 v.Paths["/"+c.RandString()] = &val 79 } 80 }, 81 func(v *SecurityScheme, c fuzz.Continue) { 82 if c.Intn(refChance) == 0 { 83 c.Fuzz(&v.Refable) 84 return 85 } 86 switch c.Intn(4) { 87 case 0: 88 v.Type = "apiKey" 89 v.Name = c.RandString() + "x" 90 switch c.Intn(3) { 91 case 0: 92 v.In = "query" 93 case 1: 94 v.In = "header" 95 case 2: 96 v.In = "cookie" 97 } 98 case 1: 99 v.Type = "http" 100 case 2: 101 v.Type = "oauth2" 102 v.Flows = make(map[string]*OAuthFlow) 103 flow := OAuthFlow{} 104 flow.AuthorizationUrl = c.RandString() + "x" 105 v.Flows["implicit"] = &flow 106 flow.Scopes = make(map[string]string) 107 flow.Scopes["foo"] = "bar" 108 case 3: 109 v.Type = "openIdConnect" 110 v.OpenIdConnectUrl = "https://" + c.RandString() 111 } 112 v.Scheme = "basic" 113 }, 114 func(v *spec.Ref, c fuzz.Continue) { 115 switch c.Intn(7) { 116 case 0: 117 *v = spec.MustCreateRef("#/components/schemas/" + randAlphanumString()) 118 case 1: 119 *v = spec.MustCreateRef("#/components/responses/" + randAlphanumString()) 120 case 2: 121 *v = spec.MustCreateRef("#/components/headers/" + randAlphanumString()) 122 case 3: 123 *v = spec.MustCreateRef("#/components/securitySchemes/" + randAlphanumString()) 124 case 5: 125 *v = spec.MustCreateRef("#/components/parameters/" + randAlphanumString()) 126 case 6: 127 *v = spec.MustCreateRef("#/components/requestBodies/" + randAlphanumString()) 128 } 129 }, 130 func(v *Parameter, c fuzz.Continue) { 131 if c.Intn(refChance) == 0 { 132 c.Fuzz(&v.Refable) 133 return 134 } 135 c.Fuzz(&v.ParameterProps) 136 c.Fuzz(&v.VendorExtensible) 137 138 switch c.Intn(3) { 139 case 0: 140 // Header param 141 v.In = "query" 142 case 1: 143 v.In = "header" 144 case 2: 145 v.In = "cookie" 146 } 147 }, 148 func(v *RequestBody, c fuzz.Continue) { 149 if c.Intn(refChance) == 0 { 150 c.Fuzz(&v.Refable) 151 return 152 } 153 c.Fuzz(&v.RequestBodyProps) 154 c.Fuzz(&v.VendorExtensible) 155 }, 156 func(v *Header, c fuzz.Continue) { 157 if c.Intn(refChance) == 0 { 158 c.Fuzz(&v.Refable) 159 return 160 } 161 c.Fuzz(&v.HeaderProps) 162 c.Fuzz(&v.VendorExtensible) 163 }, 164 func(v *ResponsesProps, c fuzz.Continue) { 165 c.Fuzz(&v.Default) 166 n := c.Intn(5) 167 for i := 0; i < n; i++ { 168 r2 := Response{} 169 c.Fuzz(&r2) 170 // HTTP Status code in 100-599 Range 171 code := c.Intn(500) + 100 172 v.StatusCodeResponses = make(map[int]*Response) 173 v.StatusCodeResponses[code] = &r2 174 } 175 }, 176 func(v *Response, c fuzz.Continue) { 177 if c.Intn(refChance) == 0 { 178 c.Fuzz(&v.Refable) 179 return 180 } 181 c.Fuzz(&v.ResponseProps) 182 c.Fuzz(&v.VendorExtensible) 183 }, 184 func(v *Operation, c fuzz.Continue) { 185 c.FuzzNoCustom(v) 186 // Do not fuzz null values into the array. 187 for i, val := range v.SecurityRequirement { 188 if val == nil { 189 v.SecurityRequirement[i] = make(map[string][]string) 190 } 191 192 for k, v := range val { 193 if v == nil { 194 val[k] = make([]string, 0) 195 } 196 } 197 } 198 }, 199 func(v *spec.Extensions, c fuzz.Continue) { 200 numChildren := c.Intn(5) 201 for i := 0; i < numChildren; i++ { 202 if *v == nil { 203 *v = spec.Extensions{} 204 } 205 (*v)["x-"+c.RandString()] = c.RandString() 206 } 207 }, 208 func(v *spec.ExternalDocumentation, c fuzz.Continue) { 209 c.Fuzz(&v.Description) 210 v.URL = "https://" + randAlphanumString() 211 }, 212 func(v *spec.SchemaURL, c fuzz.Continue) { 213 *v = spec.SchemaURL("https://" + randAlphanumString()) 214 }, 215 func(v *spec.SchemaOrBool, c fuzz.Continue) { 216 *v = spec.SchemaOrBool{} 217 218 if c.RandBool() { 219 v.Allows = c.RandBool() 220 } else { 221 v.Schema = &spec.Schema{} 222 v.Allows = true 223 c.Fuzz(&v.Schema) 224 } 225 }, 226 func(v *spec.SchemaOrArray, c fuzz.Continue) { 227 *v = spec.SchemaOrArray{} 228 if c.RandBool() { 229 schema := spec.Schema{} 230 c.Fuzz(&schema) 231 v.Schema = &schema 232 } else { 233 v.Schemas = []spec.Schema{} 234 numChildren := c.Intn(5) 235 for i := 0; i < numChildren; i++ { 236 schema := spec.Schema{} 237 c.Fuzz(&schema) 238 v.Schemas = append(v.Schemas, schema) 239 } 240 241 } 242 243 }, 244 func(v *spec.SchemaOrStringArray, c fuzz.Continue) { 245 if c.RandBool() { 246 *v = spec.SchemaOrStringArray{} 247 if c.RandBool() { 248 c.Fuzz(&v.Property) 249 } else { 250 c.Fuzz(&v.Schema) 251 } 252 } 253 }, 254 func(v *spec.Schema, c fuzz.Continue) { 255 if c.Intn(refChance) == 0 { 256 c.Fuzz(&v.Ref) 257 return 258 } 259 if c.RandBool() { 260 // file schema 261 c.Fuzz(&v.Default) 262 c.Fuzz(&v.Description) 263 c.Fuzz(&v.Example) 264 c.Fuzz(&v.ExternalDocs) 265 266 c.Fuzz(&v.Format) 267 c.Fuzz(&v.ReadOnly) 268 c.Fuzz(&v.Required) 269 c.Fuzz(&v.Title) 270 v.Type = spec.StringOrArray{"file"} 271 272 } else { 273 // normal schema 274 c.Fuzz(&v.SchemaProps) 275 c.Fuzz(&v.SwaggerSchemaProps) 276 c.Fuzz(&v.VendorExtensible) 277 c.Fuzz(&v.ExtraProps) 278 } 279 280 }, 281 }