chore: make the new policy behavior opt-in with config

This commit is contained in:
Zach Daniel 2024-09-03 22:22:46 -04:00
parent 82230f1a89
commit 06cd509e1f
7 changed files with 46 additions and 13 deletions

View file

@ -29,6 +29,8 @@ if Mix.env() == :test do
Ash.Test.Support.PolicySimple.Domain
]
config :ash, :policy, forbid_static_forbidden_reads?: false
config :ash, :custom_expressions, [Ash.Test.Expressions.JaroDistance]
config :ash, :sat_testing, true

View file

@ -256,6 +256,9 @@ config :helpdesk, :ash_domains, [Helpdesk.Support]
config :ash,
include_embedded_source_by_default?: false,
default_page_type: :keyset
config :ash, :policies,
forbid_static_forbidden_reads?: false
```
### Try our first resource out

View file

@ -36,8 +36,14 @@ defmodule Ash.Can do
opts = Keyword.put_new(opts, :run_queries?, true)
opts = Keyword.put_new(opts, :filter_with, :filter)
{resource, action_or_query_or_changeset, input} =
resource_subject_input(action_or_query_or_changeset, domain, actor, opts)
{resource, action_or_query_or_changeset, input, opts} =
case resource_subject_input(action_or_query_or_changeset, domain, actor, opts) do
{resource, action_or_query_or_changeset, input, new_opts} ->
{resource, action_or_query_or_changeset, input, Keyword.merge(new_opts, opts)}
{resource, action_or_query_or_changeset, input} ->
{resource, action_or_query_or_changeset, input, opts}
end
subject =
case action_or_query_or_changeset do
@ -182,8 +188,7 @@ defmodule Ash.Can do
domain: domain,
tenant: opts[:tenant],
actor: actor
)
|> filter_by_pkey(record), input}
), input, data: [record]}
{%resource{}, %Ash.Resource.Actions.Action{} = action, input} ->
{resource,
@ -253,13 +258,6 @@ defmodule Ash.Can do
end
end
defp filter_by_pkey(query, %resource{} = record) do
Ash.Query.do_filter(
query,
record |> Map.take(Ash.Resource.Info.primary_key(resource)) |> Map.to_list()
)
end
defp alter_source({:ok, true, query}, domain, actor, %Ash.Changeset{} = subject, opts) do
case alter_source({:ok, true}, domain, actor, subject, Keyword.put(opts, :base_query, query)) do
{:ok, true, new_subject} -> {:ok, true, new_subject, query}

View file

@ -1557,7 +1557,14 @@ defmodule Ash.Policy.Authorizer do
end
defp forbidden_due_to_strict_policy?(authorizer) do
if authorizer.for_fields || authorizer.action.type != :read do
forbid_static_forbidden_reads? =
Keyword.get(
Application.get_env(:ash, :policy, []),
:forbid_static_forbidden_reads?,
true
)
if forbid_static_forbidden_reads? || authorizer.for_fields || authorizer.action.type != :read do
true
else
authorizer.policies

View file

@ -83,7 +83,15 @@ defmodule Ash.Policy.FilterCheck do
|> filter(authorizer, opts)
|> Ash.Expr.fill_template(actor, Ash.Policy.FilterCheck.args(authorizer), context)
|> then(fn expr ->
if authorizer.for_fields || authorizer.action.type != :read ||
forbid_static_forbidden_reads? =
Keyword.get(
Application.get_env(:ash, :policy, []),
:forbid_static_forbidden_reads?,
true
)
if forbid_static_forbidden_reads? || authorizer.for_fields ||
authorizer.action.type != :read ||
context[:private][:pre_flight_authorization?] do
try_eval(expr, authorizer)
else

View file

@ -65,6 +65,12 @@ defmodule Mix.Tasks.Ash.Install do
[:default_page_type],
:keyset
)
|> Igniter.Project.Config.configure(
"config.exs",
:ash,
[:policies, :forbid_static_forbidden_reads?],
false
)
|> then(fn igniter ->
if "--example" in argv do
generate_example(igniter, argv)

View file

@ -134,6 +134,15 @@ defmodule Ash.Test.Policy.SimpleTest do
assert [] = Ash.read!(Tweet, actor: user)
end
test "Ash.can? accepts a record to determine if it can be read", %{admin: admin, user: user} do
tweet = Ash.create!(Ash.Changeset.for_create(Tweet, :create), authorize?: false)
Logger.configure(level: :debug)
assert Ash.can?({tweet, :read}, admin)
refute Ash.can?({tweet, :read}, user)
end
test "arguments can be referenced in expression policies", %{admin: admin, user: user} do
Tweet
|> Ash.Changeset.for_create(:create_foo, %{foo: "foo", user_id: admin.id}, actor: user)