diff --git a/lib/ash/actions/aggregate.ex b/lib/ash/actions/aggregate.ex index cbe1e37b..21600551 100644 --- a/lib/ash/actions/aggregate.ex +++ b/lib/ash/actions/aggregate.ex @@ -6,7 +6,8 @@ defmodule Ash.Actions.Aggregate do query = %{query | api: api} {query, opts} = Ash.Actions.Helpers.add_process_context(query.api, query, opts) - with %{valid?: true} = query <- Ash.Actions.Read.handle_attribute_multitenancy(query) do + with %{valid?: true} = query <- Ash.Actions.Read.handle_attribute_multitenancy(query), + :ok <- Ash.Actions.Read.validate_multitenancy(query) do aggregates |> Enum.group_by(fn %Ash.Query.Aggregate{} = aggregate -> diff --git a/lib/ash/actions/read/read.ex b/lib/ash/actions/read/read.ex index 022e9ae6..c828eca5 100644 --- a/lib/ash/actions/read/read.ex +++ b/lib/ash/actions/read/read.ex @@ -1155,7 +1155,8 @@ defmodule Ash.Actions.Read do end end - defp validate_multitenancy(query) do + @doc false + def validate_multitenancy(query) do if is_nil(Ash.Resource.Info.multitenancy_strategy(query.resource)) || Ash.Resource.Info.multitenancy_global?(query.resource) || query.tenant do :ok diff --git a/test/actions/multitenancy_test.exs b/test/actions/multitenancy_test.exs index 48796498..5ad2dd3f 100644 --- a/test/actions/multitenancy_test.exs +++ b/test/actions/multitenancy_test.exs @@ -132,6 +132,18 @@ defmodule Ash.Actions.MultitenancyTest do assert User |> Ash.Query.set_tenant(tenant2) |> Api.read!() == [] end + test "a record written to one tenant cannot be read from another with aggregate queries", %{ + tenant1: tenant1, + tenant2: tenant2 + } do + User + |> Ash.Changeset.new() + |> Ash.Changeset.set_tenant(tenant1) + |> Api.create!() + + assert User |> Ash.Query.set_tenant(tenant2) |> Api.list!(:name) == [] + end + test "a record can be updated in a tenant", %{tenant1: tenant1, tenant2: tenant2} do User |> Ash.Changeset.new() @@ -208,5 +220,17 @@ defmodule Ash.Actions.MultitenancyTest do result = Comment |> Api.read() assert {:error, %Ash.Error.Invalid{errors: [%Ash.Error.Invalid.TenantRequired{}]}} = result end + + test "an aggregate cannot be used without tenant specified", %{ + tenant1: tenant1 + } do + Comment + |> Ash.Changeset.new() + |> Ash.Changeset.set_tenant(tenant1) + |> Api.create!() + + result = User |> Api.count() + assert {:error, %Ash.Error.Invalid{errors: [%Ash.Error.Invalid.TenantRequired{}]}} = result + end end end