fix: CustomField policies, no system-actor fallback, guidelines

- Tests and UI pass actor for CustomField create/read/destroy; seeds use actor
- Member required-custom-fields validation uses context.actor only (no fallback)
- CODE_GUIDELINES: add rule forbidding system-actor fallbacks
This commit is contained in:
Moritz 2026-01-29 13:53:55 +01:00 committed by moritz
parent 36b5d5880b
commit 1d17c4f2dd
10 changed files with 116 additions and 43 deletions

View file

@ -750,8 +750,10 @@ defmodule MvWeb.MemberLive.IndexTest do
describe "boolean custom field filters" do
alias Mv.Membership.CustomField
# Helper to create a boolean custom field
# Helper to create a boolean custom field (uses system actor for authorization)
defp create_boolean_custom_field(attrs \\ %{}) do
system_actor = Mv.Helpers.SystemActor.get_system_actor()
default_attrs = %{
name: "test_boolean_#{System.unique_integer([:positive])}",
value_type: :boolean
@ -761,11 +763,13 @@ defmodule MvWeb.MemberLive.IndexTest do
CustomField
|> Ash.Changeset.for_create(:create, attrs)
|> Ash.create!()
|> Ash.create!(actor: system_actor)
end
# Helper to create a non-boolean custom field
# Helper to create a non-boolean custom field (uses system actor for authorization)
defp create_string_custom_field(attrs \\ %{}) do
system_actor = Mv.Helpers.SystemActor.get_system_actor()
default_attrs = %{
name: "test_string_#{System.unique_integer([:positive])}",
value_type: :string
@ -775,7 +779,7 @@ defmodule MvWeb.MemberLive.IndexTest do
CustomField
|> Ash.Changeset.for_create(:create, attrs)
|> Ash.create!()
|> Ash.create!(actor: system_actor)
end
test "mount initializes boolean_custom_field_filters as empty map", %{conn: conn} do
@ -1016,6 +1020,7 @@ defmodule MvWeb.MemberLive.IndexTest do
test "handle_params removes filter when custom field is deleted", %{conn: conn} do
conn = conn_with_oidc_user(conn)
system_actor = Mv.Helpers.SystemActor.get_system_actor()
boolean_field = create_boolean_custom_field()
# Set up filter via URL
@ -1026,8 +1031,8 @@ defmodule MvWeb.MemberLive.IndexTest do
filters_before = state_before.socket.assigns.boolean_custom_field_filters
assert filters_before[boolean_field.id] == true
# Delete the custom field
Ash.destroy!(boolean_field)
# Delete the custom field (requires actor with destroy permission)
Ash.destroy!(boolean_field, actor: system_actor)
# Navigate again - filter should be removed since custom field no longer exists
{:ok, view2, _html} =
@ -1328,7 +1333,7 @@ defmodule MvWeb.MemberLive.IndexTest do
members = [member_with_true, member_with_false, member_without_value]
filters = %{to_string(boolean_field.id) => true}
all_custom_fields = Mv.Membership.CustomField |> Ash.read!()
all_custom_fields = Mv.Membership.CustomField |> Ash.read!(actor: system_actor)
result =
MvWeb.MemberLive.Index.apply_boolean_custom_field_filters(
@ -1378,7 +1383,7 @@ defmodule MvWeb.MemberLive.IndexTest do
members = [member_with_true, member_with_false, member_without_value]
filters = %{to_string(boolean_field.id) => false}
all_custom_fields = Mv.Membership.CustomField |> Ash.read!()
all_custom_fields = Mv.Membership.CustomField |> Ash.read!(actor: system_actor)
result =
MvWeb.MemberLive.Index.apply_boolean_custom_field_filters(
@ -1417,7 +1422,7 @@ defmodule MvWeb.MemberLive.IndexTest do
members = [member1, member2]
filters = %{}
all_custom_fields = Mv.Membership.CustomField |> Ash.read!()
all_custom_fields = Mv.Membership.CustomField |> Ash.read!(actor: system_actor)
result =
MvWeb.MemberLive.Index.apply_boolean_custom_field_filters(
@ -1507,7 +1512,7 @@ defmodule MvWeb.MemberLive.IndexTest do
to_string(boolean_field2.id) => true
}
all_custom_fields = Mv.Membership.CustomField |> Ash.read!()
all_custom_fields = Mv.Membership.CustomField |> Ash.read!(actor: system_actor)
result =
MvWeb.MemberLive.Index.apply_boolean_custom_field_filters(
@ -1538,7 +1543,7 @@ defmodule MvWeb.MemberLive.IndexTest do
members = [member]
filters = %{fake_id => true}
all_custom_fields = Mv.Membership.CustomField |> Ash.read!()
all_custom_fields = Mv.Membership.CustomField |> Ash.read!(actor: system_actor)
result =
MvWeb.MemberLive.Index.apply_boolean_custom_field_filters(