Reenable filter predicate analysis prior to authorization
- Dominant language
- Elixir
- Stars
- 2.5k
- Forks
- 426
- Avg merge
- 23h 26m
- Merged PRs (30d)
- 46
Description
Something that we used to do, but turned off (for various reasons I won't go into here), is analysis of filter statements, using filter predicate comparison. The code that powers this is still available and in use for functions like:
`Ash.Query.subset_of(query, expr)`
## How does this help with policies?
This can help significantly with the performance around authorizing access to data. For example, lets say you have a policy like this:
```elixir
policy action_type(:read) do
authorize_if expr(owner_id == ^actor(:id))
end
```
And an actor, like this `%User{id: 1}`
Then, you make a request:
```elixir
Resource
|> Ash.Query.filter(owner_id == 2)
|> Ash.read!(actor: %User{id: 1})
```
What we will currently do is produce this query ultimately:
```elixir
Resource
|> Ash.Query.filter(owner_id == 2 and owner_id == 1)
|> Ash.read!()
```
However, we can return to leveraging our filter predicate comparison. Here is an example implementation of comparing to equality filter predicates:
```elixir
@impl Ash.Filter.Predicate
def compare(
%__MODULE__{left: left, right: left_right},
%__MODULE__{left: left, right: right_right}
) do
if Comp.equal?(left_right, right_right) do
:mutually_inclusive
else
:mutually_exclusive
end
end
```
We can use this code to determine that `x == 1` and `x == 2` is *mutually exclusive*, and determine that it is *therefore not possible for policies to pass*.
At this point, we will skip running the query entirely, and instead return an empty data set. This means that forbidden requests can cost practically zero performance penalty against an API 🥳
We have the tools to do this, we just need to reenable it and test it :)
Contributor guide
Research direction
Start by tracing authorization's use of Ash.Query.subset_of/2 and the Ash.Filter.Predicate.compare callbacks. Reproduce the mutually exclusive filters shown in the issue, then inspect the existing authorization tests or add coverage for returning an empty data set without running the query. Done means compatible filters still authorize normally and contradictory policy/request filters are short-circuited.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- elixir
- Domain
- authorization, performance
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100