Last question for the day :slightly_smiling_face: ...
# help
m
Last question for the day 🙂 I'm trying to arbitrarily permit access to entities in my system based on some given tag. So you might have some role
TAGGED_READ_ONLY
that is for entities with
tag=foo
. Similarly you might have the same role conditioned on
tag=bar
. The tag itself is arbitrary depending on customer requirements. On the flip side a resource might have a basket of tags. I want to avoid creating a role for each tag combination (using a git store for policies right now). The role + tag need to be considered together. So right now I've got something like this. However, something like this works at the evaluation step if a resource is present, but doesn't translate well when doing query planning. Is there a way to represent this that query planning might better understand ?
Copy code
P.attr.taggedRoles.exists(
            tr,
            tr.role == 'TAGGED_READ_ONLY' && tr.tag in R.attr.tags
          )
d
As far as I understand, taggedRoles is an array of objects
{ role, tag }
. If it can be shaped as a map
{ role: [tag] }
the expression can be rewritten:
P.attr.taggedRoles['TAGGED_READ_ONLY'].exists(t, t in R.attr.tags)
. Or
intersect(P.attr.taggedRoles['TAGGED_READ_ONLY'], R.attr.tags)
. The main idea is
P.attr.taggedRoles['TAGGED_READ_ONLY']
can be evaluated in the query planner, so the produced AST won’t contain any reference to the role.
m
Good tip! Both those spit out things much more comprehensible. Seems a queryPlanToPrisma limitation might be getting the intersection or "exists in" to map to a prisma query ? Neither variations seem to be handled well by queryPlanToPrisma. Does that match your expectation? However, something like P.attr.taggedRoles['foo'] in R.attr.tags can be. But limits the number of tags you might have associated with one of these roles.
Similar with
hasIntersection(P.attr.taggedRoles['foo'], R.attr.tags)
d
Yes, I think queryPlanToPrisma doesn’t support it yet.
P.attr.taggedRoles[‘foo’] in R.attr.tags can be. But limits the number of tags you might have associated with one of these roles.
That should work, but I guess having a single tag per role is not ideal.
m
Gotcha, will investigate further then. Might be something we can translate on our end or maybe contribute to 😛 Another observation, if the queryPlanToPrisma isn't able to translate it returns an empty object. Is this a bit problematic from an authorization perspective? If you drop that in a query it won't restrict anything.
d
Alternatively, the original expression can be processed by the query planner differently since the target of the
exists
method is known. For example,
[1, 2, -3].exists(t, t > R.attr.value)
can be translated to
1 > R.attr.value OR 2 > R.attr.value OR -3 > R.attr.value
. I believe this can be handled by the queryPlanToPrisma
The query planner doesn’t support this optimisation. I’ll create an issue.
Or conversion from
exists
to
expr1 OR expr2 OR … exprN
can be done by queryPlanToPrisma.
m
For example,
[1, 2, -3].exists(t, t > R.attr.value)
can be translated to
1 > R.attr.value OR 2 > R.attr.value OR -3 > R.attr.value
.
This translation would require knowing the [1, 2, 3] ahead of time though correct? If it's part of the principal it's unknown until call time.
d
Yes, I mean the call time.
m
To make sure I follow, are you saying
P.attr['taggedRoles'].exists(t, t in R.attr.tags)
can be done or cannot be done?
d
For example,
[1, 2, -3].exists(t, t > R.attr.value)
can be translated to
1 > R.attr.value OR 2 > R.attr.value OR -3 > R.attr.value
.
I meant this as a runtime optimisation by cerbos. In your policies, you write
P.attr['taggedRoles'].exists(t, t in R.attr.tags)
I meant this as a runtime optimisation by cerbos.
Possible optimisation. It hasn’t been implemented.
a
Just an FYI we literally just published a new version of the Prisma adapter https://www.npmjs.com/package/@cerbos/orm-prisma The API has changed so it is a major version and addresses a number of things that have been raised (it now does relations for example) - (shout to community member @Nabil 🙂 )
if the queryPlanToPrisma isn’t able to translate it returns an empty object
This is handled now also and throws an exception. I will check for you use case specifically tomorrow
m
Timely, I'll give it a look 🙂