This is a test code for ash_state_machine.
test "test transition_state" do
assert object = Ashex.run_create!(Object, :create)
assert %{state: :done} = Ashex.run_update!(object, :progress)
end
test "prevent create with non initial state by AshStateMachine.Checks.ValidNextState" do
assert {:error, %Ash.Error.Forbidden{}} =
Ashex.run_create(Object, :create, params: %{state: :done})
end
test "fail when progress twice" do
assert object = Ashex.run_create!(Object, :create)
assert %{state: :done} = object = Ashex.run_update!(object, :progress)
assert Ashex.can?({object, :progress}, nil) == false
assert {:error, %Ash.Error.Forbidden{}} = Ashex.run_update(object, :progress, actor: nil)
end
end
assert Ashex.can?({object, :progress}, nil) == false
This assertion passes, so I think there is no permission.
assert {:error, %Ash.Error.Forbidden{}} = Ashex.run_update(object, :progress, actor: nil)
But this assertion does not pass, because the Object.progress action fails with Ash.Error.Invalid.
I think action call without permission should return Ash.Error.Forbidden.
And Ash.Error.Invalid looks like a validation error.
Is this a bug?
Ash.can?
is “is valid and is allowed” by default. Try using Ash.can
and see what kind of error is returned.
“valid” means validity of policies?
Not the validity determined by validations?
I’m referring to the validity of the changeset itself. The reason for this is that validations and changes run before authorization.
Any changes or validations that should run after authorization should use before_action?: true
(in the case of validations) or Ash.Changeset.before_action
in the case of changes.
I think I have bad understandig at policy
and can
function.
So I need to study more about them.
I have a small question.
Would you give me a scenario, when does the can
function return {:ok, :maybe}
?
{:ok, :maybe}
would be returned in the case of filter policies on read actions, when the data to be read isn’t provided, and run_queries?
is set to false
. So to answer we’d have to run the queries, so we’d have to say :maybe
.
Thank you for your explanation.
Ok, now I got it about my original question.
My Conclusions
Ash.can
return {:ok, true}
when policy pass (even if validation fail)
return {:ok, false}
when policy fail
Error returned by action
return Ash.Error.Forbidden
when only policy fail
return Ash.Error.Invalid
when only validation fail
return Ash.Error.Invalid
when policy and validation fail
cannot determine policy passed/failed by error class
Why return Ash.Error.Invalid
when policy and validation fail?
Is this correct? @zachdaniel
I got these conclusions with below test codes.
This is my ash_state_machine
test code.
defmodule SonetLib.AshStateMachine.CommonTest do
use SonetLib.DataCase
defmodule Object do
use Ash.Resource,
domain: TestDomain,
authorizers: [Ash.Policy.Authorizer],
extensions: [AshStateMachine]
attributes do
uuid_v7_primary_key :id
end
state_machine do
initial_states [:pending]
default_initial_state :pending
transitions do
transition :progress, from: :pending, to: :done
end
This file has been truncated. show original
And this is my authorization_validation_priority_test.exs
.
defmodule SonetLib.Ash.Research.AuthorizationValidationPriorityTest do
use SonetLib.DataCase
defmodule Object do
use Ash.Resource,
domain: TestDomain,
authorizers: [Ash.Policy.Authorizer]
attributes do
uuid_v7_primary_key :id
attribute :name, :string, public?: true
end
actions do
create :create do
primary? true
accept :*
validate attributes_present(:name)
end
end
This file has been truncated. show original
rapidfsub:
return Ash.Error.Invalid
when policy and validation fail
cannot determine policy passed/failed by error class
A better way to phrase this would be that when running the action, policies aren’t run on invalid actions.
1 Like