Skip to content

Fix/root refs#27

Draft
MadMockers wants to merge 4 commits intojacksmith15:masterfrom
MadMockers:fix/root-refs
Draft

Fix/root refs#27
MadMockers wants to merge 4 commits intojacksmith15:masterfrom
MadMockers:fix/root-refs

Conversation

@MadMockers
Copy link
Copy Markdown

@MadMockers MadMockers commented Oct 18, 2022

Any related Github Issues?: add link here

  • Added support for references which point to within the object containing the
    $ref key.

Check list

Before asking for a review

  • Target branch is master
  • make test passes locally. (See comments - all unit tests are passing)
  • [Unreleased] section in CHANGELOG.md is updated.
  • I reviewed the "Files changed" tab and self-annotated anything unexpected.

Before review (reviewer)

  • All of the above are checked and true. Review ALL items. If not, return the PR to the author.
  • Continuous Integration is passing. If not, return the PR to the author.

After merge (reviewer)

  • Any issues that may now be closed are closed.

@MadMockers
Copy link
Copy Markdown
Author

MadMockers commented Oct 18, 2022

Unsure if this is particularly meant to be valid behaviour, however json-schema allows it and I've been doing this personally.

I keep all my definitions in #/definitions/*, including the "root" schema itself. I then have a $ref in the document root that points into #/definitions/some_def.

e.g:

definitions:
  my_def:
    type: integer

$ref: "#/definitions/my_def"

This is problematic as the resolver doesn't expect the the json pointer to point inside the object itself. Without this fix, a recursion error is generated as the document is loaded over and over. This is similar to the check for immediate circular references, however where that is certainly not resolvable, arguably this configuration is resolvable.

The solution implemented was to ignore $ref if the next part of the URI being searched for is present.

With regards to make test - All unit tests are passing locally, however there's linting failures that exist on master.

@jacksmith15
Copy link
Copy Markdown
Owner

jacksmith15 commented Oct 18, 2022

I can believe that some JSON Schema implementations support this, but its explicitly against the JSON Reference specification:

Any members other than "$ref" in a JSON Reference object SHALL be ignored.

https://datatracker.ietf.org/doc/html/draft-pbryan-zyp-json-ref-03

This means the "definitions" key in the object here should be ignored by the implementation - and as such the reference doesn't resolve.

I think this is part of the spec for good reason, as otherwise it produces ambiguous situations in which its not clear what a reference should resolve to. See my example in the PR comment to illustrate.

I'm interested to understand which JSON Schema implementations support this, and how they resolve the example below.

Comment on lines +56 to +58
isinstance(doc, abc.Mapping)
and isinstance(doc.get("$ref"), str)
and not next_part in doc
Copy link
Copy Markdown
Owner

@jacksmith15 jacksmith15 Oct 18, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this could produce issues. Consider:

foo:
    $ref: "#/bar/value"
bar:
    $ref: "#/baz"
    value: "bar_value"
baz:
    value: "baz_value"

Then what should RefDict("file.yaml")["foo"] resolve to? According to spec, it should resolve to "baz_value", but I think with this change, it would resolve to "bar_value".

Copy link
Copy Markdown
Author

@MadMockers MadMockers Oct 18, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes this is true. I'll have to explore if there's a better way to determine if a reference is pointing within itself. If the sidestepping of $ref is only enabled in that situation, I think that resolves the issue you raise.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm open to suggestions on how to identify that! I have a suspicion it might be an tricky/expensive thing to compute..

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a test for this scenario (which is currently failing), will look into resolving.

Copy link
Copy Markdown
Author

@MadMockers MadMockers Oct 19, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've re-written this with a more complete solution which takes this issue into account.

A $ref is now only ignored when the RefPointer being resolved comes across itself, and the resolver has more parts of the URI to resolve. This allows the existing RefPointer resolve process to continue.

If there is not more to resolve, then the reference is actually circular on itself directly, and the existing behaviour which handles that is triggered (by not ignoring the $ref).

Copy link
Copy Markdown
Author

@MadMockers MadMockers Oct 19, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies this doesn't actually handle my original use-case now if a reference appears inside the definitions.. I've marked this PR as draft and will re-visit. Feel free to also close it and I'll re-create once I have a working solution.

definitions:
  foo:
    $ref: "#/definitions/bar"
  bar:
    type: integer

$ref: "#/definitions/foo"

@MadMockers
Copy link
Copy Markdown
Author

MadMockers commented Oct 18, 2022

Any members other than "$ref" in a JSON Reference object SHALL be ignored.

Is this referring only to the syntax of the reference itself, as opposed to looking up the reference within an otherwise valid JSON document? If this is the case, then a valid reference syntax is an object with $ref, with all other keys being ignored.

I admit I'm looking for reasons for this to be valid, however am standing on dubious semantics.

I'm interested to understand which JSON Schema implementations support this, and how they resolve the example below.

I'm using https://pypi.org/project/jsonschema/ which handles this use-case.

Test that if a JSON object has keys in addition to the `$ref` key that
the additional keys are ignored.
@MadMockers MadMockers force-pushed the fix/root-refs branch 3 times, most recently from d7497ed to 2733562 Compare October 19, 2022 07:13
Fixed references which point to within the object containing the `$ref`
key.
@MadMockers MadMockers marked this pull request as draft October 19, 2022 09:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants