Having a small policy that doesn't seem to ever be called

I have a policy where I need an actor to be present for three different actions, but the policies don't seem to be called. The policies:
policies do
policy action([:read, :accept_invite, :create_invite]) do
authorize_if actor_present()
end

policy always() do
forbid_if always()
end
end
policies do
policy action([:read, :accept_invite, :create_invite]) do
authorize_if actor_present()
end

policy always() do
forbid_if always()
end
end
Code to test:
IrisBackend.Families.Invite
|> Ash.Changeset.for_create(:create_invite, %{}, actor: nil)
|> Ash.create!()
IrisBackend.Families.Invite
|> Ash.Changeset.for_create(:create_invite, %{}, actor: nil)
|> Ash.create!()
The code in the :create_invite-action assumes that a property on the actor exists, and since the actor is nil everything explodes in a KeyError. Have I done any obvious mistake in the policies?
Solution:
yeah, in this context, the policies don't guarantee an actor. you could wrap this in before_action and than you'd know that if you reach the hook that there is an actor beccause of the policy, or you could just handle the actor being nil case Map.get(context.actor || %{}, :group_id) do which i would probably do
Jump to solution
6 Replies
barnabasj
barnabasj5d ago
what code? changes are run before auth, hooks are not
Andreas Ekeroot @ work
Oh. Got it. Okay, what I'm really trying to do is to get the policies to return a ForbiddenError when there's no authenticated GraphQL user. Does changes run before auth for ash_graphql too?
barnabasj
barnabasj5d ago
ash_graphql is calling the actions the same way, there is always a changeset constructed first, which runs the changes and than the action is executed, auth happens before execution what does your change code look like?
Andreas Ekeroot @ work
Got it. My change code looks like this:
create :create_invite do
change fn changeset, context ->
case context.actor.group_id do
nil ->
Ash.Changeset.add_error(changeset,
message:
"The person creating an invite for a group must be member of that group, and this is not the case here."
)

group_id ->
# Create the invite here, not relevant for the question
end
end
create :create_invite do
change fn changeset, context ->
case context.actor.group_id do
nil ->
Ash.Changeset.add_error(changeset,
message:
"The person creating an invite for a group must be member of that group, and this is not the case here."
)

group_id ->
# Create the invite here, not relevant for the question
end
end
Solution
barnabasj
barnabasj5d ago
yeah, in this context, the policies don't guarantee an actor. you could wrap this in before_action and than you'd know that if you reach the hook that there is an actor beccause of the policy, or you could just handle the actor being nil case Map.get(context.actor || %{}, :group_id) do which i would probably do
Andreas Ekeroot @ work
Thank you. Then I've misunderstood when policies are run and how they work.

Did you find this page helpful?