Open LilaRest opened 1 month ago
I think this will be a very useful feature, but not straightforward to achieve. The reason behind is when evaluating access policies, ZenStack combines all rules in a model together and injects into a Prisma query (for better performance); so when a violation happens, it doesn't really know which rule caused the violation.
Maybe we can consider introducing a "debug" mode just for diagnosis purposes. When that mode is ON, when a violation occurs, it automatically retries the same operation by applying the policy rules one by one to know which one allowed/denied it.
ZenStack combines all rules in a model together and injects into a Prisma query (for better performance); so when a violation happens, it doesn't really know which rule caused the violation.
Doesn't Zod provide paths inside of error's issues? That could help linking the Zod output to the specific field that led to the error.
ZenStack combines all rules in a model together and injects into a Prisma query (for better performance); so when a violation happens, it doesn't really know which rule caused the violation.
Doesn't Zod provide paths inside of error's issues? That could help linking the Zod output to the specific field that led to the error.
Most of ZenStack's access control enforcement is not done via Zod in the Node runtime, but through injecting into database queries (and thus evaluated by the database, through Prisma). For example, when evaluating an "update" rule during an updateMany
call, instead of pulling the records out of the database and checking which rows meet the update condition, ZenStack injects the "update" policies into the where
clause of updateMany
, so the filtering and updating can be efficiently done by the db altogether.
This is even the case for "create". You may have a policy like this:
model Post {
owner User @relation(...)
@@allow('create', !owner.banned)
}
To evaluate the "create" condition, we actually need to access its owner
relation. ZenStack's general approach is to, inside a transaction, create the entity and then see if we can read it back with the "create" policies as filter; if not, revert. In some cases, e.g., when the create policies don't involve any relation, we internally short-circuit the database read with an in-memory check. But it's considered an internal optimization, and the general approach is to rely on the database-side evaluation.
So given this approach, generally speaking we don't really know which specific policy failed a mutation, as they are evaluated as a whole on the db side ... In some specific cases we can, but I'm not sure how to wrap it into an intuitive feature 😂
This documentation has a bit more background information: https://zenstack.dev/docs/the-complete-guide/part1/under-the-hood
Is your feature request related to a problem? Please describe. Actually, once a policy is violated, ZenStack returns the following error object, which is not super descriptive for consumers. That becomes an even more important problem if the ZenStack-generated API is to be exposed to other developers as a public API or in an SDK.
Describe the solution you'd like. It'd be gorgeous to allow a third
message
parameter into@@allow
and@@deny
clauses. Something like that:Then, on policy violation, ZenStack would return the following: