From 6b9330198335b2adc3727e489cd543578f052c3d Mon Sep 17 00:00:00 2001 From: Dave Shanley Date: Tue, 30 Apr 2024 10:26:05 -0400 Subject: [PATCH] Addressed issue #75 --- go.mod | 2 +- go.sum | 4 +- requests/validate_body_test.go | 137 +++++++++++++++++++++++++++++++++ requests/validate_request.go | 15 +++- 4 files changed, 153 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 0994be1..c1144d7 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/pb33f/libopenapi-validator go 1.21 require ( - github.com/pb33f/libopenapi v0.16.3 + github.com/pb33f/libopenapi v0.16.4 github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 github.com/stretchr/testify v1.9.0 github.com/vmware-labs/yaml-jsonpath v0.3.2 diff --git a/go.sum b/go.sum index 0cba75c..3c3e2a9 100644 --- a/go.sum +++ b/go.sum @@ -54,8 +54,8 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= -github.com/pb33f/libopenapi v0.16.3 h1:ozo0vYdeP6r+qAXb+Kg1MOy6QrTxSgNpoD3nKuw/HA8= -github.com/pb33f/libopenapi v0.16.3/go.mod h1:PEXNwvtT4KNdjrwudp5OYnD1ryqK6uJ68aMNyWvoMuc= +github.com/pb33f/libopenapi v0.16.4 h1:mX81EkBS7cbJZeJiw2ovXchGGHCLvfj26gGs4jL1XDU= +github.com/pb33f/libopenapi v0.16.4/go.mod h1:PEXNwvtT4KNdjrwudp5OYnD1ryqK6uJ68aMNyWvoMuc= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= diff --git a/requests/validate_body_test.go b/requests/validate_body_test.go index 246a191..4bc8717 100644 --- a/requests/validate_body_test.go +++ b/requests/validate_body_test.go @@ -6,6 +6,7 @@ package requests import ( "bytes" "encoding/json" + "fmt" "net/http" "testing" @@ -1194,3 +1195,139 @@ components: assert.Equal(t, "invalid character '}' looking for beginning of object key string", errors[0].SchemaValidationErrors[0].Reason) } + +func TestValidateBody_SchemaNoType_Issue75(t *testing.T) { + + spec := `{ + "openapi": "3.0.1", + "info": { + "title": "testing", + "description": "

This is for testing purpose

", + "version": "1.0", + "x-targetEndpoint": "https://mocktarget.apigee.net/json" + }, + "servers": [ + { + "url": "https://some-url.com" + } + ], + "paths": { + "/path1": { + "put": { + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "anyOf": [ + { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1 + }, + "age": { + "type": "integer" + } + }, + "required": [ + "name" + ] + }, + { + "type": "object", + "properties": { + "email": { + "type": "string" + }, + "address": { + "type": "string" + } + }, + "required": [ + "email" + ] + } + ] + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/path2": { + "get": { + "parameters": [ + { + "name": "X-My-Header", + "in": "header", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/path3": { + "get": { + "parameters": [ + { + "name": "id", + "in": "query", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + } +} +` + + doc, err := libopenapi.NewDocument([]byte(spec)) + if err != nil { + fmt.Println("error while creating open api spec document", err) + return + } + + req, err := http.NewRequest("PUT", "/path1", nil) + if err != nil { + fmt.Println("error while creating new HTTP request", err) + return + } + + req.Header.Set("Content-Type", "application/json") + + v3Model, errs := doc.BuildV3Model() + if len(errs) > 0 { + fmt.Println("error while building a Open API spec V3 model", errs) + return + } + + reqBodyValidator := NewRequestBodyValidator(&v3Model.Model) + isSuccess, valErrs := reqBodyValidator.ValidateRequestBody(req) + + assert.False(t, isSuccess) + assert.Len(t, valErrs, 1) + assert.Equal(t, "PUT request body is empty for '/path1'", valErrs[0].Message) + +} diff --git a/requests/validate_request.go b/requests/validate_request.go index 7b6b969..3a26e86 100644 --- a/requests/validate_request.go +++ b/requests/validate_request.go @@ -74,6 +74,17 @@ func ValidateRequestSchema( // no request body? but we do have a schema? if len(requestBody) <= 0 && len(jsonSchema) > 0 { + + line := -1 + col := -1 + if schema.Type != nil { + line = schema.GoLow().Type.KeyNode.Line + col = schema.GoLow().Type.KeyNode.Column + } else { + line = schema.ParentProxy.GetSchemaKeyNode().Line + col = schema.ParentProxy.GetSchemaKeyNode().Line + } + // cannot decode the request body, so it's not valid violation := &errors.SchemaValidationFailure{ Reason: "request body is empty, but there is a schema defined", @@ -86,8 +97,8 @@ func ValidateRequestSchema( Message: fmt.Sprintf("%s request body is empty for '%s'", request.Method, request.URL.Path), Reason: "The request body is empty but there is a schema defined", - SpecLine: schema.GoLow().Type.KeyNode.Line, - SpecCol: schema.GoLow().Type.KeyNode.Line, + SpecLine: line, + SpecCol: col, SchemaValidationErrors: []*errors.SchemaValidationFailure{violation}, HowToFix: errors.HowToFixInvalidSchema, Context: string(renderedSchema), // attach the rendered schema to the error