ash-project / ash

A declarative, extensible framework for building Elixir applications.
https://www.ash-hq.org
MIT License
1.57k stars 208 forks source link

Allow marking actions as internal to prevent exposing them via APIs #1271

Open smt116 opened 2 months ago

smt116 commented 2 months ago

In complex systems, there are often actions that suppose to only be used internally. For example, a way of user lookup by some custom key or creating a record. Currently, they can be added to policies with authorize_if always() or used only with authorized?: false.

Using a policy introduces a risk of exposing them in the API at some point. On the other hand, authorized?: false breaks the authorization circuit by not passing the current action context down the line (e.g., to nested actions).

It would be great if Ash could allow for something like internal? true on action definition. That property would be used when building APIs' actions, by raising a compilation error.

zachdaniel commented 2 months ago

To align with what that means generally, we'd say something like private? true in the action. Although to align with 3.0 it would be something like public? false (and if I had thought of it before 3.0 it would default to false 😢). This seems like a good idea to me. It would be up to extensions to check that they are only using public actions, but thats how everything else already is so that should be fine.

zachdaniel commented 2 months ago

I've labeled this as a "good first issue", as implementing it in core will be easy. Once that is done, issues will need to be opened in AshGraphql, AshJsonApi, and AshPhoenix (not creating forms for private actions? maybe, maybe not) to track the usage of this metadata there.

zachdaniel commented 2 months ago

I think what we would likely still require, however, is something like this in policies:

bypass private_action?() do
  authorize_if always()
end

But it becomes safer to include a policy like this because you know for a fact that no public interface contains it.

smt116 commented 2 months ago

Once that is done, issues will need to be opened in AshGraphql, AshJsonApi, and AshPhoenix (not creating forms for private actions? maybe, maybe not)

I would say that a form is still kind of an application interface. IMHO, non-public actions should never be used outside of the system. Unfortunately, it means no console usage too (without authorized?: false), but better be consistent than having exceptions in the logic. It should be impossible to interact with non-public actions using any kind of "human accessible interface".

zachdaniel commented 2 months ago

Console usage would be quite hard to detect unfortunately. I'm not sure if it's reasonable.

zachdaniel commented 2 months ago

Because if it uses process dictionary for example internal action calls by the action would think they are in the console too

smt116 commented 2 months ago

Right 🤔. Good enough