From 4fffeeaaa02d6c112c5414086d0d73d3974113a5 Mon Sep 17 00:00:00 2001 From: Moritz Date: Thu, 8 Jan 2026 22:54:51 +0100 Subject: [PATCH] Fix: Seeds use admin actor instead of NoActor bypass This ensures seeds work correctly with the new fail-closed NoActor policy in production, using proper authorization instead of bypass. --- priv/repo/seeds.exs | 46 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/priv/repo/seeds.exs b/priv/repo/seeds.exs index 3fb2bad..7f5b322 100644 --- a/priv/repo/seeds.exs +++ b/priv/repo/seeds.exs @@ -162,6 +162,17 @@ if admin_role do |> Ash.update!() end +# Load admin user with role for use as actor in member operations +# This ensures all member operations have proper authorization +# If admin role creation failed, we cannot proceed with member operations +admin_user_with_role = + if admin_role do + admin_user + |> Ash.load!(:role) + else + raise "Failed to create or find admin role. Cannot proceed with member seeding." + end + # Load all membership fee types for assignment # Sort by name to ensure deterministic order all_fee_types = @@ -236,7 +247,8 @@ Enum.each(member_attrs_list, fn member_attrs -> member = Membership.create_member!(member_attrs_without_fee_type, upsert?: true, - upsert_identity: :unique_email + upsert_identity: :unique_email, + actor: admin_user_with_role ) # Only set membership_fee_type_id if member doesn't have one yet (idempotent) @@ -247,7 +259,7 @@ Enum.each(member_attrs_list, fn member_attrs -> |> Ash.Changeset.for_update(:update_member, %{ membership_fee_type_id: member_attrs_without_status.membership_fee_type_id }) - |> Ash.update!() + |> Ash.update!(actor: admin_user_with_role) else member end @@ -299,7 +311,7 @@ Enum.each(member_attrs_list, fn member_attrs -> if cycle.status != status do cycle |> Ash.Changeset.for_update(:update, %{status: status}) - |> Ash.update!() + |> Ash.update!(actor: admin_user_with_role) end end) end @@ -371,13 +383,15 @@ Enum.with_index(linked_members) Membership.create_member!( Map.put(member_attrs_without_fee_type, :user, %{id: user.id}), upsert?: true, - upsert_identity: :unique_email + upsert_identity: :unique_email, + actor: admin_user_with_role ) else # User already has a member, just create the member without linking - use upsert to prevent duplicates Membership.create_member!(member_attrs_without_fee_type, upsert?: true, - upsert_identity: :unique_email + upsert_identity: :unique_email, + actor: admin_user_with_role ) end @@ -391,7 +405,7 @@ Enum.with_index(linked_members) member |> Ash.Changeset.for_update(:update_member, %{membership_fee_type_id: fee_type.id}) - |> Ash.update!() + |> Ash.update!(actor: admin_user_with_role) else member end @@ -435,7 +449,7 @@ Enum.with_index(linked_members) end) # Create sample custom field values for some members -all_members = Ash.read!(Membership.Member) +all_members = Ash.read!(Membership.Member, actor: admin_user_with_role) all_custom_fields = Ash.read!(Membership.CustomField) # Helper function to find custom field by name @@ -463,7 +477,11 @@ if hans = find_member.("hans.mueller@example.de") do custom_field_id: field.id, value: value }) - |> Ash.create!(upsert?: true, upsert_identity: :unique_custom_field_per_member) + |> Ash.create!( + upsert?: true, + upsert_identity: :unique_custom_field_per_member, + actor: admin_user_with_role + ) end end) end @@ -488,7 +506,11 @@ if greta = find_member.("greta.schmidt@example.de") do custom_field_id: field.id, value: value }) - |> Ash.create!(upsert?: true, upsert_identity: :unique_custom_field_per_member) + |> Ash.create!( + upsert?: true, + upsert_identity: :unique_custom_field_per_member, + actor: admin_user_with_role + ) end end) end @@ -514,7 +536,11 @@ if friedrich = find_member.("friedrich.wagner@example.de") do custom_field_id: field.id, value: value }) - |> Ash.create!(upsert?: true, upsert_identity: :unique_custom_field_per_member) + |> Ash.create!( + upsert?: true, + upsert_identity: :unique_custom_field_per_member, + actor: admin_user_with_role + ) end end) end