Skip to content

Commit

Permalink
OpenAPI vendor module update (#399)
Browse files Browse the repository at this point in the history
* Update module

* Fix muxer

* Fix validation

* Update error messages in the tests

* Update test due to better validation

* Changelog
  • Loading branch information
Alex Schneider authored Dec 1, 2021
1 parent 64bd2d3 commit a0484d8
Show file tree
Hide file tree
Showing 63 changed files with 2,458 additions and 1,877 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ Unreleased changes are available as `avenga/couper:edge` container.
* exclude file descriptor limit startup-logs for Windows ([#396](https://github.com/avenga/couper/pull/396), [#383](https://github.com/avenga/couper/pull/383))
* possible race conditions while updating JWKS for the [JWT access control](./docs/REFERENCE.md#jwt-block) ([#398](https://github.com/avenga/couper/pull/398))

* **Dependencies**
* Update modules for [OpenAPI](./docs/REFERENCE.md#openapi-block) validation ([#399](https://github.com/avenga/couper/pull/399))
* `github.com/getkin/kin-openapi v0.49.0` => `github.com/getkin/kin-openapi v0.83.0`

---

## [1.6](https://github.com/avenga/couper/releases/tag/1.6)
Expand Down
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ require (
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1
github.com/docker/go-units v0.4.0
github.com/fatih/color v1.10.0
github.com/getkin/kin-openapi v0.49.0
github.com/getkin/kin-openapi v0.83.0
github.com/hashicorp/hcl/v2 v2.10.1
github.com/jimlambrt/go-oauth-pkce-code-verifier v0.0.0-20201220003123-6363600dffda
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
Expand Down Expand Up @@ -57,8 +57,8 @@ require (
github.com/jonboulle/clockwork v0.2.0 // indirect
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e // indirect
github.com/mattermost/xml-roundtrip-validator v0.0.0-20201208211235-fe770d50d911 // indirect
github.com/mattn/go-colorable v0.1.8 // indirect
github.com/mattn/go-isatty v0.0.12 // indirect
github.com/mattn/go-colorable v0.1.9 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/sergi/go-diff v1.2.0 // indirect
go.opentelemetry.io/otel/internal/metric v0.23.0 // indirect
Expand Down
10 changes: 10 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,12 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.m
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/getkin/kin-openapi v0.49.0 h1:nKSq662fS0kZ11+Wu3FLg3GQGL0UuH1VxF8wV1QuDEU=
github.com/getkin/kin-openapi v0.49.0/go.mod h1:ZJSfy1PxJv2QQvH9EdBj3nupRTVvV42mkW6zKUlRBwk=
github.com/getkin/kin-openapi v0.83.0 h1:qQbfSsapSPuRS73xhElJ85bWFo2REHNXBXAQ1kqqlCE=
github.com/getkin/kin-openapi v0.83.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
Expand Down Expand Up @@ -164,6 +168,7 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
Expand Down Expand Up @@ -201,8 +206,12 @@ github.com/mattermost/xml-roundtrip-validator v0.0.0-20201208211235-fe770d50d911
github.com/mattermost/xml-roundtrip-validator v0.0.0-20201208211235-fe770d50d911/go.mod h1:qccnGMcpgwcNaBnxqpJpWWUiPNr5H3O8eDgGV9gT5To=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
Expand Down Expand Up @@ -443,6 +452,7 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210915083310-ed5796bab164 h1:7ZDGnxgHAMw7thfC5bEos0RDAccZKxioiWBhfIe+tvw=
golang.org/x/sys v0.0.0-20210915083310-ed5796bab164/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
Expand Down
4 changes: 2 additions & 2 deletions handler/transport/backend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,15 +192,15 @@ func TestBackend_RoundTrip_Validation(t *testing.T) {
http.MethodPost,
"/get",
"backend validation error",
"'POST /get': Path doesn't support the HTTP method",
"'POST /get': method not allowed",
},
{
"invalid request, IgnoreRequestViolations",
&config.OpenAPI{File: "testdata/upstream.yaml", IgnoreRequestViolations: true, IgnoreResponseViolations: true},
http.MethodPost,
"/get",
"",
"'POST /get': Path doesn't support the HTTP method",
"'POST /get': method not allowed",
},
{
"invalid response",
Expand Down
22 changes: 12 additions & 10 deletions handler/validation/openapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ import (

"github.com/getkin/kin-openapi/openapi3"
"github.com/getkin/kin-openapi/openapi3filter"
"github.com/getkin/kin-openapi/routers"
"github.com/getkin/kin-openapi/routers/legacy"

"github.com/avenga/couper/config/request"
"github.com/avenga/couper/eval"
)

var routers sync.Map
var routersStore sync.Map

type OpenAPI struct {
options *OpenAPIOptions
Expand All @@ -31,10 +33,10 @@ func NewOpenAPI(opts *OpenAPIOptions) *OpenAPI {
}
}

func (v *OpenAPI) getRouter(key, origin string) (*openapi3filter.Router, error) {
router, exists := routers.Load(key)
func (v *OpenAPI) getRouter(key, origin string) (routers.Router, error) {
router, exists := routersStore.Load(key)
if !exists {
clonedSwagger := cloneSwagger(v.options.swagger)
clonedSwagger := cloneSwagger(v.options.doc)

var newServers []string
for _, s := range clonedSwagger.Servers {
Expand Down Expand Up @@ -69,16 +71,16 @@ func (v *OpenAPI) getRouter(key, origin string) (*openapi3filter.Router, error)
clonedSwagger.AddServer(&openapi3.Server{URL: ns})
}

r := openapi3filter.NewRouter()
if err := r.AddSwagger(clonedSwagger); err != nil {
r, err := legacy.NewRouter(clonedSwagger)
if err != nil {
return nil, err
}

routers.Store(key, r)
routersStore.Store(key, r)
return r, nil
}

return router.(*openapi3filter.Router), nil
return router.(routers.Router), nil
}

func (v *OpenAPI) ValidateRequest(req *http.Request, key string) (*openapi3filter.RequestValidationInput, error) {
Expand All @@ -101,7 +103,7 @@ func (v *OpenAPI) ValidateRequest(req *http.Request, key string) (*openapi3filte
return nil, nil
}

route, pathParams, err := router.FindRoute(req.Method, &serverURL)
route, pathParams, err := router.FindRoute(req)
if err != nil {
err = fmt.Errorf("'%s %s': %w", req.Method, req.URL.Path, err)
if ctx, ok := req.Context().Value(request.OpenAPI).(*OpenAPIContext); ok {
Expand Down Expand Up @@ -185,7 +187,7 @@ func (v *OpenAPI) ValidateResponse(beresp *http.Response, requestValidationInput
return nil
}

func cloneSwagger(s *openapi3.Swagger) *openapi3.Swagger {
func cloneSwagger(s *openapi3.T) *openapi3.T {
sw := *s
// this is not a deep clone; we only want to add servers
sw.Servers = s.Servers[:]
Expand Down
6 changes: 3 additions & 3 deletions handler/validation/openapi_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ type OpenAPIOptions struct {
ignoreRequestViolations bool
ignoreResponseViolations bool
filterOptions *openapi3filter.Options
swagger *openapi3.Swagger
doc *openapi3.T
}

// NewOpenAPIOptions takes a list of openAPI configuration due to merging configurations.
Expand Down Expand Up @@ -45,7 +45,7 @@ func NewOpenAPIOptionsFromBytes(openapi *config.OpenAPI, bytes []byte) (*OpenAPI
return nil, nil
}

swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromData(bytes)
doc, err := openapi3.NewLoader().LoadFromData(bytes)
if err != nil {
return nil, fmt.Errorf("error loading openapi file: %w", err)
}
Expand All @@ -63,6 +63,6 @@ func NewOpenAPIOptionsFromBytes(openapi *config.OpenAPI, bytes []byte) (*OpenAPI
},
ignoreRequestViolations: openapi.IgnoreRequestViolations,
ignoreResponseViolations: openapi.IgnoreResponseViolations,
swagger: swagger,
doc: doc,
}, nil
}
4 changes: 2 additions & 2 deletions handler/validation/openapi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,10 @@ func TestOpenAPIValidator_ValidateRequest(t *testing.T) {
wantBody bool
wantErrLog string
}{
{"GET without required query", "/a?b", nil, false, "backend validation error: Parameter 'b' in query has an error: must have a value: must have a value"},
{"GET without required query", "/a?b", nil, false, `backend validation error: parameter "b" in query has an error: value is required but missing: value is required but missing`},
{"GET with required query", "/a?b=value", nil, false, ""},
{"GET with required path", "/a/value", nil, false, ""},
{"GET with required path missing", "/a//", nil, false, "backend validation error: Parameter 'b' in query has an error: must have a value: must have a value"},
{"GET with required path missing", "/a//", nil, false, `backend validation error: parameter "b" in query has an error: value is required but missing: value is required but missing`},
{"GET with optional query", "/b", nil, false, ""},
{"GET with optional path param", "/b/a", nil, false, ""},
{"GET with required json body", "/json", strings.NewReader(`["hans", "wurst"]`), true, ""},
Expand Down
4 changes: 0 additions & 4 deletions handler/validation/testdata/backend_04_openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@ servers:
variables:
sub:
default: 'api'
- url: 'http://{broken/v1'
variables:
broken:
default: https://api.example.com
- url: 'https://{sub}.example.com/anything'
variables:
sub:
Expand Down
27 changes: 15 additions & 12 deletions server/mux.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import (
"strings"

"github.com/getkin/kin-openapi/openapi3"
"github.com/getkin/kin-openapi/openapi3filter"
"github.com/getkin/kin-openapi/pathpattern"
"github.com/getkin/kin-openapi/routers"
"github.com/getkin/kin-openapi/routers/legacy/pathpattern"

"github.com/avenga/couper/config"
"github.com/avenga/couper/config/request"
Expand All @@ -24,6 +24,7 @@ import (
type Mux struct {
endpointRoot *pathpattern.Node
fileRoot *pathpattern.Node
handler map[*routers.Route]http.Handler
opts *runtime.MuxOptions
spaRoot *pathpattern.Node
}
Expand Down Expand Up @@ -57,6 +58,7 @@ func NewMux(options *runtime.MuxOptions) *Mux {
endpointRoot: &pathpattern.Node{},
fileRoot: &pathpattern.Node{},
spaRoot: &pathpattern.Node{},
handler: make(map[*routers.Route]http.Handler),
}

for path, h := range opts.EndpointRoutes {
Expand Down Expand Up @@ -118,21 +120,22 @@ func (m *Mux) mustAddRoute(root *pathpattern.Node, methods []string, path string
serverOpts = optsHandler.Options()
}

node.Value = &openapi3filter.Route{
Method: method,
Path: path,
Handler: handler,
node.Value = &routers.Route{
Method: method,
Path: path,
Server: &openapi3.Server{Variables: map[string]*openapi3.ServerVariable{
serverOptionsKey: {Default: serverOpts},
serverOptionsKey: {Default: fmt.Sprintf("%#v", serverOpts)},
}},
}

m.handler[node.Value.(*routers.Route)] = handler
}

return m
}

func (m *Mux) FindHandler(req *http.Request) http.Handler {
var route *openapi3filter.Route
var route *routers.Route

node, paramValues := m.match(m.endpointRoot, req)
if node == nil {
Expand Down Expand Up @@ -160,7 +163,7 @@ func (m *Mux) FindHandler(req *http.Request) http.Handler {
}
}

route, _ = node.Value.(*openapi3filter.Route)
route, _ = node.Value.(*routers.Route)

pathParams := make(request.PathParameter, len(paramValues))
paramKeys := node.VariableNames
Expand All @@ -181,7 +184,7 @@ func (m *Mux) FindHandler(req *http.Request) http.Handler {
ctx = context.WithValue(ctx, request.PathParams, pathParams)
*req = *req.WithContext(ctx)

return route.Handler
return m.handler[route]
}

func (m *Mux) match(root *pathpattern.Node, req *http.Request) (*pathpattern.Node, []string) {
Expand All @@ -196,8 +199,8 @@ func (m *Mux) hasFileResponse(req *http.Request) (http.Handler, bool) {
return nil, false
}

route := node.Value.(*openapi3filter.Route)
fileHandler := route.Handler
route := node.Value.(*routers.Route)
fileHandler := m.handler[route]
unprotectedHandler := getChildHandler(fileHandler)
if fh, ok := unprotectedHandler.(*handler.File); ok {
return fileHandler, fh.HasResponse(req)
Expand Down
3 changes: 3 additions & 0 deletions vendor/github.com/getkin/kin-openapi/jsoninfo/field_info.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions vendor/github.com/getkin/kin-openapi/jsoninfo/marshal.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions vendor/github.com/getkin/kin-openapi/jsoninfo/unmarshal.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit a0484d8

Please sign in to comment.