graphiti-api / graphiti-rails

MIT License
54 stars 28 forks source link

Error responses missing exception message details #65

Open ef4 opened 3 years ago

ef4 commented 3 years ago

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:

https://github.com/graphiti-api/graphiti-rails/blob/4a8a065f9c67cf0c3bcedfb7c8ac3da033560e57/lib/graphiti/rails.rb#L46-L49

This results in detail: nil in the jsonapi errors.

richmolj commented 3 years ago

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 commented 3 years ago

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 commented 3 years ago

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 commented 3 years ago

Yes, Iā€™m talking about writes. If you try to set a belongs_to so it will point at an existing resource, and that resource 404s, the whole request 404s.

On Sun, Jan 24, 2021 at 1:42 PM Lee Richmond notifications@github.com wrote:

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.

ā€” You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/graphiti-api/graphiti-rails/issues/65#issuecomment-766410609, or unsubscribe https://github.com/notifications/unsubscribe-auth/AACN6MQ5LGQOQIU2RZQTHQLS3RS23ANCNFSM4WJTS7PA .

richmolj commented 3 years ago

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 commented 3 years ago

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

richmolj commented 3 years ago

PR: https://github.com/graphiti-api/graphiti/pull/310