Skip to content
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

feat: add modifiedSchema on preExecution hooks #641

Merged
merged 10 commits into from Nov 11, 2021

Conversation

Eomm
Copy link
Contributor

@Eomm Eomm commented Nov 9, 2021

Opening this PR to get some feedback.

I'm working on this issue: mercurius-js/auth#43
The target of that issue is to modify the output schema for inspection queries like so

app.graphql.addHook('preExecution', async function filterHook (schema, document, context) {

  // removes those objects that the user has not access to
  const filteredSchema = auth.filterDirectives(schema, authSchema)

  return {
    schema: filteredSchema
  }
})

The inspection query is a standard query that is being executed on the app.graphql.schema object.

To let the user (and in this case the mercurius/auth plugin) change the schema where the query is executed and affect the output results, the preExecution hook may manage a schema replacing.

Note that I did not use app.graphql.transformSchema because it would replace the initial/original schema: this is unwanted: the target here is to replace the schema only for a single request execution.

Doing so, every request may change the schema accordingly to its data (such as client's role&permissions).

This PR lacks documentation, but I would like to know if you are OK with this solution before add it.
Feel free to suggest some additional tests too

Thanks

@mcollina
Copy link
Collaborator

mcollina commented Nov 9, 2021

To let the user (and in this case the mercurius/auth plugin) change the schema where the query is executed and affect the output results, the preExecution hook may manage a schema replacing.

This seems a really bad idea. What about concurrency issues?

@Eomm
Copy link
Contributor Author

Eomm commented Nov 9, 2021

What about concurrency issues?

I don't expect those issues since the "temporary-schema" is used on the request's scope and it must not affect the global schema that remains the default.

I can arrange a test for it as well

@Eomm
Copy link
Contributor Author

Eomm commented Nov 9, 2021

This seems a really bad idea.

I did not find a way to implement the desired logic using the actual API, such as the onResolution hook, mainly because there is not a reference to the (auth) resolver to execute to decide if a Graph FIELD or OBJECT should be returned or not.

I agree that this could be a dangerous feature to use with caution - the risk is a broken API.
Could we protect the user from misusing this feature?

Copy link
Collaborator

@mcollina mcollina left a comment

Choose a reason for hiding this comment

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

Can you add docs?

Copy link
Collaborator

@mcollina mcollina left a comment

Choose a reason for hiding this comment

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

lgtm

index.js Outdated Show resolved Hide resolved
Copy link
Collaborator

@mcollina mcollina left a comment

Choose a reason for hiding this comment

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

Please add a few test with jit enabled.

index.js Outdated
}

// minJit is 0 by default
if (shouldCompileJit) {
if (shouldCompileJit && !modifiedSchema) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This should be documented. I think the same problem might happen for modifiedDocument too - we might end up fixing a bug.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

I think the same problem might happen for modifiedDocument

I think the modifiedDocument is worth being jit'ed it is a consistent update.
For example, a developer is renaming a field from old to new

lib/handlers.js Outdated
return {
modifiedSchema,
modifiedDocument,
modifiedQuery: print(request.document)
Copy link
Collaborator

Choose a reason for hiding this comment

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

are we using modifiedQuery anywhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is used on the gateway implementation

Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe make it a getter?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It was unused.
Removed

The same name is used on the preGatewayExecutionHandler

index.js Outdated
if (shouldCompileJit && !modifiedSchema) {
cached.jit = compileQuery(fastifyGraphQl.schema, modifiedDocument || document, operationName)
if (shouldCompileJit) {
if (!modifiedSchema) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
if (!modifiedSchema) {
if (!modifiedSchema || !modifiedDocument) {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If we change the schema but not the document the jit is executed against the "origin" schema.
Is it useful creating the jit when the document will be executed using the modifiedSchema?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't understand.

I think the modifiedDocument is worth being jit'ed it is a consistent update.
For example, a developer is renaming a field from old to new

What makes me itchy in jiting this is that the hook takes the context as an argument, therefore those changes could be based on user credentials. Compiling those in is a potential security hazard.

What we really need is another field to defer this to the user. Having a cacheable or jit property would put the developer in charge of what is happening.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I get the point, I will try to arrange a security test for this case.

The current PR's code blocks the jit execution when the schema is modified by the hook.
The suggested code enables the jit when the user changes the modifiedSchema property that seems unwanted.

What we really need is another field to defer this to the user. Having a cacheable or jit property would put the developer in charge of what is happening.

Clear, I would add it in a follow-up PR because there are a few cases that must be discussed or would you like to upgrade this PR instead?

The doubts concern:

  • should we provide the cache counter to the hook function using the context?
  • does the cacheable property have priority over the jit option?

Copy link
Collaborator

Choose a reason for hiding this comment

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

should we provide the cache counter to the hook function using the context?

Unsure about this

does the cacheable property have priority over the jit option?

Yes

Copy link
Collaborator

@mcollina mcollina left a comment

Choose a reason for hiding this comment

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

lgtm

@Eomm Eomm mentioned this pull request Nov 10, 2021
Copy link
Contributor

@jonnydgreen jonnydgreen left a comment

Choose a reason for hiding this comment

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

Looks good! As well as the getter added on the modifiedQuery could we also update the typings and the typing tests? https://github.com/mercurius-js/mercurius/blob/master/index.d.ts#L788

Copy link
Contributor

@jonnydgreen jonnydgreen left a comment

Choose a reason for hiding this comment

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

LGTM

@mcollina mcollina merged commit 5589295 into mercurius-js:master Nov 11, 2021
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.

None yet

3 participants