python-openapi / openapi-core

Openapi-core is a Python library that adds client-side and server-side support for the OpenAPI v3.0 and OpenAPI v3.1 specification.
BSD 3-Clause "New" or "Revised" License
299 stars 132 forks source link

SpecFactory doesn't keep scope state resulting in unresolvable relative references #98

Open ghost opened 6 years ago

ghost commented 6 years ago

I have a set of files that form a spec that fully validates with openapi-spec-validator. It can find all references, but openapi-core cannot and after much debugging I figured out why. The various generators that are started in the SpecFactory, specifically the PathsGenerator and everything it drives, only keep reference to the top-level spec_url. When you trace through openapi-spec-validator, you see that with every file change the derefencer.resolver_manager.resolver._scopes_stack increases and the current location is appended to it and used to resolve any references. But these generators do not do anything with the scope, so cannot resolve the relative path references and the base_uri always remains the same.

ghost commented 6 years ago

I added test cases that show the problem, but not sure how to proceed from here. Would appreciate any pointers to why this is failing.

ghost commented 5 years ago

So in openapi_spec_validator, we have a decorator that wraps the dereferencer and sets ['x-scope'] before diving in further. The generators in openapi_core do not have a similar mechanism and the basic error is here:

  1. OperationsGenerator.generate() dereferences the path.
  2. Before returning, Dereferencer.dereference() from openapi_spec_validator, exits the context and calls finally() which resets the scope.
  3. Now the parameter list needs to be resolved at the yield statement in generate. The parameter list (from debugger) looks like this in my case: <class 'list'>: [{'$ref': '../../common/parameters.yaml#/pagination-page'}, {'$ref': '../../common/parameters.yaml#/pagination-size'}, {'$ref': './parameters.yaml#/ordering'}] and path is <class 'dict'>: {'$ref': './user-panel/orders/get.yaml'}, finally scope_stack = <class 'list'>: ['file:///home/melvyn/hg/polyrepo/button3d/apidocs/openapi/openapi.yaml'].

So at this point the parameter references do not have the correct scope. But if you put the paths into a separate file, then the operations have the problem, so it's a problem for any generator that is instantiated from a file not in the root directory.

We either need a different dereferencer that checks target for things to deref before returning (not possible imo, since you don't know what the refs objects are) or initialize the generators with a dereferencer that has the correct scope.

p1c2u commented 5 years ago

157 can potentially solve this issue too

gjcarneiro commented 9 months ago

Noting here that this is still an issue for me too.