Annotating manual actions and custom changes for policies
My current understanding is that policy builtins like
changing
and selecting
won't see into manual actions at all, and that they will see into custom changes to the degree expressed by the returned changeset and not further.
In the case that one requires a manual action, or to overcome any limitations for custom changes, is it possible to annotate the action, indicating to Ash that the manual
is going to affect certain attributes or otherwise do things that a policy might care about?18 Replies
So
changing
and selecting
will see everything up until the manual action invocation
which should typically be enough, since everything in the manual action is hand-written code that should only do what the given user can do, right?
What you can potentially do is make sure to call a different non-manual action after calling the manual one
and write your policies against that non-manual one(Very roughly) something like:
?
There are some cases—such as those involving recursion—where I could maybe turn reads into a modify query, but not more than that. Similarly for relationships, I can make them manuals that define the
ash_postgres_*
callbacks, but not turn them into Ash relationships at the moment.
For sure pushing the policy logic into the manual works, which is mostly what I've been doing. Generally, I'm quite interested in ideas for blurring the lines between policies and actions, as do filter checks for example.It might help to have a concrete example to talk about
Sure, for example I'd like to use a recursive query to return all documents that are children of a specified
Document
—nil
representing the root document. I believe I need a manual action for the time being, but I still want to control which attributes of each Document
the user is allowed to select based on roles etc.
Definitely something that can be accomplished in the manual action itself, no question.Well, if you have policies on the select statement from the parent query
and then you pass down the parent query's select
then you should be good right?
In this case, the parent is simply passed in by id (or
nil
), and all documents are retrieved using a single recursive query in a manual.
Am I right in thinking you're talking about the parent being selected in an initial read action that would hit policy checks? 😄Well, when I call the manual action, I provide a query
So you'd pass down the select/query from the parent action, and write policies against the select I provided from the outset
Right on, that makes sense. So the
selecting
policy is introspecting the incoming query, not so much how the action decides to satisfy it? Rather maybe a combination of both.
To what degree does that apply to writes? Seems like less can be assumed about a write from its arguments.So creates/updates/destroys actually generally work the same way.
All that we do is run changes/preparations and then authorize, we don't actually do authorization based on the result of running all of the before action hooks
The idea is that if there is behavior that you're adding in a hook, its internal in some way, and you should be able to infer enough from the user's initial request to do your authorization.
Ok, that makes sense, definitely a good piece of info though 🙂
Then for the example I described, and most manual reads, policies using
selecting
should basically work, because the policy will check the query up front, even if it's manual. This assumes the manual respects the user's query, but that's not a big deal since it should anyway.
For writes, it won't be able to infer anything from the incoming arguments in the case it's a manual.correct, usually for manual actions its best to end up writing policies about the arguments themselves and/or delegating to a different action w/ policies
Is it possible to mix
changes
with manual
for the purposes of annotation? There would then be a pretty straightforward path to creating a change that would "pretend" to set the attributes that the manual would affect.yes 🙂
changes are all run, and the changeset given to a manual action will honor all of that
and before/after action hooks are still run
the manual action just takes over the final "do the thing" step
Cool, will make a macro for now.
Looking forward to those extendable builtins 😄
What do you mean?
I was looking at this: https://github.com/ash-project/spark/issues/33
GitHub
Add
Spark.Builtins
· Issue #33 · ash-project/sparkOne of the spark types we have is {:spark_function_behaviour, ... that allows specifying a "builtins module" which is a module from which to show autocompletions automatically. What we sh...
But maybe one can already add and this is just for autocomplete?
What I was referring to was the ability to augment a schema defined in another DSL/extension, e.g. now I have this for the annotations:
(and maybe there is a nicer way to do that besides setting the attribute to its current value)
Honestly I'm confused why you'd rather use the
changes_attributes/1
macro at all
I'd personally just put this:
in my resource
alternatively, I'd define simulate_change_attributes/1
that returns the change tuple
and say change simulate_change_attributes([:foo, :bar])