fix: properly enforce tenancy on all mutative actions

This commit is contained in:
Zach Daniel 2024-07-06 13:41:58 -04:00
parent 9de400de9c
commit e1dffc0c0c
4 changed files with 63 additions and 3 deletions

View file

@ -509,6 +509,15 @@ defmodule Ash.Actions.Create do
defp manage_relationships(other, _, _, _), do: other
defp set_tenant(changeset) do
changeset =
case changeset.data do
%{__metadata__: %{tenant: tenant}} ->
Ash.Changeset.set_tenant(changeset, tenant)
_ ->
changeset
end
if changeset.tenant &&
Ash.Resource.Info.multitenancy_strategy(changeset.resource) == :attribute do
attribute = Ash.Resource.Info.multitenancy_attribute(changeset.resource)
@ -517,7 +526,15 @@ defmodule Ash.Actions.Create do
Ash.Changeset.force_change_attribute(changeset, attribute, attribute_value)
else
changeset
if is_nil(Ash.Resource.Info.multitenancy_strategy(changeset.resource)) ||
Ash.Resource.Info.multitenancy_global?(changeset.resource) || changeset.tenant do
changeset
else
Ash.Changeset.add_error(
changeset,
Ash.Error.Invalid.TenantRequired.exception(resource: changeset.resource)
)
end
end
end

View file

@ -267,6 +267,14 @@ defmodule Ash.Actions.Destroy do
end
defp set_tenant(changeset) do
changeset =
case changeset.data do
%{__metadata__: %{tenant: tenant}} ->
Ash.Changeset.set_tenant(changeset, tenant)
_ ->
changeset
end
if changeset.tenant &&
Ash.Resource.Info.multitenancy_strategy(changeset.resource) == :attribute do
attribute = Ash.Resource.Info.multitenancy_attribute(changeset.resource)
@ -276,7 +284,15 @@ defmodule Ash.Actions.Destroy do
Ash.Changeset.filter(changeset, [{attribute, attribute_value}])
else
changeset
if is_nil(Ash.Resource.Info.multitenancy_strategy(changeset.resource)) ||
Ash.Resource.Info.multitenancy_global?(changeset.resource) || changeset.tenant do
changeset
else
Ash.Changeset.add_error(
changeset,
Ash.Error.Invalid.TenantRequired.exception(resource: changeset.resource)
)
end
end
end

View file

@ -622,7 +622,15 @@ defmodule Ash.Actions.Update do
Ash.Changeset.filter(changeset, expr(^ref(attribute) == ^attribute_value))
else
changeset
if is_nil(Ash.Resource.Info.multitenancy_strategy(changeset.resource)) ||
Ash.Resource.Info.multitenancy_global?(changeset.resource) || changeset.tenant do
changeset
else
Ash.Changeset.add_error(
changeset,
Ash.Error.Invalid.TenantRequired.exception(resource: changeset.resource)
)
end
end
end
end

View file

@ -311,6 +311,14 @@ defmodule Ash.Actions.MultitenancyTest do
|> Ash.create!()
end
test "an error is produced when a tenant is not specified" do
assert_raise Ash.Error.Invalid, ~r/require a tenant to be specified/, fn ->
User
|> Ash.Changeset.for_create(:create, %{})
|> Ash.create!()
end
end
test "a record written to one tenant cannot be read from another", %{
tenant1: tenant1,
tenant2: tenant2
@ -411,6 +419,17 @@ defmodule Ash.Actions.MultitenancyTest do
assert User |> Ash.Query.set_tenant(tenant2) |> Ash.read!() == []
end
test "updates require a tenant as well", %{tenant1: tenant1} do
assert_raise Ash.Error.Invalid, ~r/require a tenant to be specified/, fn ->
User
|> Ash.Changeset.for_create(:create, %{}, tenant: tenant1)
|> Ash.create!()
|> Map.update!(:__metadata__, &Map.delete(&1, :tenant))
|> Ash.Changeset.for_update(:update, %{})
|> Ash.update!()
end
end
test "a record for a different tenant cant be updated from the other one", %{
tenant1: tenant1,
tenant2: tenant2