Membership FilterCheck
Hello lovely people š
Iāve been working on a custom SpaceMemberFilter policy check (using
Ash.Policy.FilterCheck
) with a goal to authorize access if the actor is a member of the space associated with a given resource (optionally filtered by actorās role in given space).
I took inspiration from Ash.Policy.Check.RelatesToActorVia
, but instead of comparing to a single actor ID, I need to check whether the resourceās space_id
is in the list of the actorās valid space memberships.
I attached the whole code, It works, but Iām worried about:
- Performance: I have to precompute the actorās valid space IDs in a separate query (get_actor_space_ids/2) and then use an in expression against them. It feels clunky and potentially expensive for actors with many memberships.
- Elegance: I tried several approaches with expr/exists to avoid the extra query and push everything into one correlated subquery, but always hit Data layer does not support unrelated exists expressions.
So my question is:
Is there a cleaner or more idiomatic way in Ash to implement this check (ideally using exists/2 or similar) without doing the extra query to get all space IDs first?
Thanks in advance š10 Replies
Can you upgrade ash, ash_postgres and ash_sql to the latest and try the unrelated aggregates again?
I updated to most recent versions, but still no luck
š¤
okay try updating again š
I hadn't released the fix yet
Still no luck with converting it into an expression-like syntax (the shared code is working), I am just trying to find a cleaner way to write it. I was thinking about something like this:
Instead of approaching by fetching the space IDs of the current actor.
That looks roughly correct to me, but I think you may need something like this:
If you have relationships that point to the space_membership, then you can do
exists([:path, :to, :space_membership], user_id == ^actor(:id))
with this approach it returns:
no function clause matching in :lists.droplast/1
š¤š¤ weird
maybe a bug
whats the stacktrace?
Sorry for the delay - my weekend ran longer than expected.
I replaced the expression in my filter with the one you suggested (for simplicity, I didnāt include roles at this stage):
I then tried calling my actions from different resources.
When I call the read action (via the GraphQL API) on the
space_membership
resource which has a space_id
field directly and the policy set to:
I get back the attached error (could not fit it into a message).
Similarly, when I call the read action for my user
resource (which has a relationship to space via space_membership
) and set the policy as:
I get a similar error (attached), so basically, the same issue occurs in both cases.š¤ something is very strange there š¢ I think I'll need a repro. Please reproduce it in a project and then open an issue šāāļø
Hereās the repository with the testing app. For the sake of simplicity, Iāve also added seed files for users and spaces. In theory, that should be enough to call the read actions on both the
user
and space_membership
resources. The code we're dealing with lives at space_member_filter.ex
.
The app is configured to use the DATABASE_URL
environment variable, so no additional configuration should be required for database. It also expects some values at SECRET_KEY_BASE
, and TOKEN_SIGNING_SECRET
to be set.