-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix CoerceArgumentValues() hasValue #1056
base: main
Are you sure you want to change the base?
Conversation
✅ Deploy Preview for graphql-spec-draft ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
The latest build of GraphQL.NET does not suffer from this issue either. Test added in graphql-dotnet/graphql-dotnet#3762 to be sure. |
d7ff2cb
to
47e4904
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great find!
Fixes a bug discovered whilst carefully evaluating
CoerceArgumentValues()
that leads to "undefined value leakage" and potential null pointer exception if strictly following the spec. GraphQL.js does not suffer this, so this is a spec bug rather than an implementation bug.Consider the following schema:
And the following GraphQL query:
Imagine that we send an empty object (
{}
) as the variable values.Coercing the variableValues according to https://spec.graphql.org/draft/#CoerceVariableValues() we get an empty object (
{}
).Fast-forward to https://spec.graphql.org/draft/#CoerceArgumentValues():
coercedValues = {}
argumentValues = { arg: $var }
fieldName = 'field'
field named {fieldName}.
argumentDefinitions = { arg: String! = "defaultValue" }
argumentName = 'arg'
argumentType = String!
defaultValue = 'defaultValue'
{argumentName}. 🐛 !!!BUG!!!
hasValue = true
becauseargumentValues
does provide the variable$var
as the value for the argument 'arg'{argumentName}.
argumentValue = $var
Yes, $var is a variable
variableName = 'var'
{variableName}. 🐛 !!!BUG!!! This does not fire, but
hasValue
is already {true} by the above.{variableName}. 🐛 !!!BUG!!!
value = undefined
NOT TRIGGERED
NOT TRIGGERED
since hasValue is true{defaultValue}.
not {true} or {value} is {null}, raise a field error.
NOT TRIGGERED
becausehasValue
is {true} and value is not {null} (it is undefined!)Yes, it is
It is not, it is undefined
{null}.
It is!
{value}.
coercedValues[argumentName] = undefined
(sincevalue
is undefined){argumentType}, raise a field error.
input coercion rules of {argumentType}.
{coercedValue}.
Expectation:
coercedValues = { arg: "defaultValue" }
Actual result:
coercedValues = { arg: undefined }
arg
is non-null string -> NPE! 💥Essentially the phrase "Let {hasValue} be {true} if {argumentValues} provides a value for the name {argumentName}" is at best ambiguous and at worst plain wrong, since the next two lines get the "value" for {argumentName} and then check to see if this {value} is a variable.
This PR fixes this issue by only setting
hasValue
totrue
when the value is explicitly resolved via the two branches: variable and non-variable.There is no need for a GraphQL.js PR for this since GraphQL.js already follows the expected behavior; reproduction: