fuzz.go 6.1 KB

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