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  }