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

Error responses missing exception message details #65

Open
ef4 opened this issue Jan 19, 2021 · 7 comments
Open

Error responses missing exception message details #65

ef4 opened this issue Jan 19, 2021 · 7 comments

Comments

@ef4
Copy link

ef4 commented Jan 19, 2021

Graphiti's error classes have a lot of message methods with helpful errors details. But as far as I can tell, graphiti-rails has the rendering of these disabled because it doesn't pass detail: :exception to rescue-registry here:

register_exception Graphiti::Errors::InvalidRequest, status: 400, handler: Graphiti::Rails::InvalidRequestHandler
register_exception Graphiti::Errors::RecordNotFound, status: 404, handler: Graphiti::Rails::ExceptionHandler
register_exception Graphiti::Errors::RemoteWrite, status: 400, handler: Graphiti::Rails::ExceptionHandler
register_exception Graphiti::Errors::SingularSideload, status: 400, handler: Graphiti::Rails::ExceptionHandler

This results in detail: nil in the jsonapi errors.

@richmolj
Copy link
Collaborator

I think the intent was to hide implementation details from clients - but sounds like we should at least pass detail if the environment is not production, and ideally make this a config flag. @wagenet thoughts?

@ef4
Copy link
Author

ef4 commented Jan 23, 2021

A motivating example here is when a subresource raises RecordNotFound. It's not really useful to obscure which resource caused the problem, because an attacker can just ask explicitly about those resources individually to see which one 404s. Refusing to say which subresource 404'd just slows down legitimate debugging.

(I would also argue that it's incorrect HTTP semantics, because a 404 is supposed to be referring to the URL you hit, and if that represents a valid resource, it's incorrect to send a 404 just because the body referred to some different missing resource. But that's a bigger can of worms.)

Taking the information hiding argument to its logical conclusion, we should always send status code 500 and call it a day, because anything else leaks information to potential attackers. I don't think that's a good argument, I think helpful errors are a critical part of API design and they don't hurt security.

@richmolj
Copy link
Collaborator

Refusing to say which subresource 404'd just slows down legitimate debugging.

Pardon the top-of-my-head thinking here, but IIRC this shouldn't happen. The external interface Resource#find raises this error, but when sideloading we use the internal Resource#_find. The difference is the latter doesn't raise errors if the record isn't found. In fact Graphiti doesn't have the concept (yet 😊 !) of a required belongs_to relationship (we treat it as optional). This comment is certainly valid if we did, but in the present day I'm not sure when/how you'd get a 404 when an included resource isn't found. Maybe something with writes, rather than ?include? Or maybe I'm just totally misremembering.

(I would also argue that it's incorrect HTTP semantics, because a 404 is supposed to be referring to the URL you hit, and if that represents a valid resource, it's incorrect to send a 404 just because the body referred to some different missing resource. But that's a bigger can of worms.)

I think this is a fair view, but to play devil's advocate - the conceptual resource here is the entire graph, not just the top-level node. So you could say 404 is valid because the entire graph wasn't found. TBH I can see both sides here and don't particularly have a dog in the fight, just sharing the thinking. Either way I think you have a valid point about the error message being specific to the nested resource, rather than something wrapped with context.

I don't think that's a good argument, I think helpful errors are a critical part of API design and they don't hurt security.

I actually agree with this, but have run into many people who do not (including, unfortunately, the security review team at my company 😝 ). Either way, I think it should be dead easy to deliver the full message, environment variable is the easiest I can think of.

Also want to note https://www.graphiti.dev/guides/concepts/error-handling#displaying-raw-errors though it's a slightly different use case.

@ef4
Copy link
Author

ef4 commented Jan 24, 2021 via email

@richmolj
Copy link
Collaborator

Gotcha - specifically for writes, sounds like we should catch this error and handle it with validations. That would give you both the nested context and helpful error message you're looking for. Does that work for you?

There's still work to do with this general issue, but that sounds to me like the best way to handle that specific use case.

@ef4
Copy link
Author

ef4 commented Jan 25, 2021

Yes, a 422 pointing to the relationship that's a dangling reference would be great.

richmolj pushed a commit to richmolj/graphiti that referenced this issue Jan 30, 2021
[This issue](graphiti-api/graphiti-rails#65)
raised the idea that we should be treating a missing sideposted record
as a validation, not a 401.

In the course of this work I found [this older PR](graphiti-api#214),
which initially raised the same point iin [this comment](graphiti-api#214 (comment)).

I very much agree that this should be a validation error, not a 401, but
it breaks backwards compatibility. So, you can opt-in to this behavior
with `Graphiti.config.raise_on_missing_sidepost = false`. We should
consider this a best practice going forward and note it in the blog.
@richmolj
Copy link
Collaborator

PR: graphiti-api/graphiti#310

richmolj pushed a commit to richmolj/graphiti that referenced this issue Feb 1, 2021
[This issue](graphiti-api/graphiti-rails#65)
raised the idea that we should be treating a missing sideposted record
as a validation, not a 401.

In the course of this work I found [this older PR](graphiti-api#214),
which initially raised the same point iin [this comment](graphiti-api#214 (comment)).

I very much agree that this should be a validation error, not a 401, but
it breaks backwards compatibility. So, you can opt-in to this behavior
with `Graphiti.config.raise_on_missing_sidepost = false`. We should
consider this a best practice going forward and note it in the blog.
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

No branches or pull requests

2 participants