diff --git a/changelog.d/config-db-unknown-module.fix b/changelog.d/config-db-unknown-module.fix new file mode 100644 index 000000000..05a6a2b2f --- /dev/null +++ b/changelog.d/config-db-unknown-module.fix @@ -0,0 +1 @@ +Do not crash at boot or in the AdminAPI config listing when a ConfigDB setting refers to a module that no longer exists diff --git a/lib/pleroma/config/transfer_task.ex b/lib/pleroma/config/transfer_task.ex index 48cb158ca..731d05e8b 100644 --- a/lib/pleroma/config/transfer_task.ex +++ b/lib/pleroma/config/transfer_task.ex @@ -48,6 +48,7 @@ defmodule Pleroma.Config.TransferTask do settings = (Repo.all(ConfigDB) ++ deleted_settings) |> Enum.reject(&ConfigDB.static?/1) + |> Enum.reject(&(&1.group == :invalid_atom or &1.key == :invalid_atom)) |> Enum.map(&merge_with_default/1) started_applications = Application.started_applications() diff --git a/lib/pleroma/ecto_type/config/atom.ex b/lib/pleroma/ecto_type/config/atom.ex index c44d655e0..dad640f3d 100644 --- a/lib/pleroma/ecto_type/config/atom.ex +++ b/lib/pleroma/ecto_type/config/atom.ex @@ -5,6 +5,8 @@ defmodule Pleroma.EctoType.Config.Atom do use Ecto.Type + require Logger + def type, do: :atom def cast(key) when is_atom(key) do @@ -17,8 +19,17 @@ defmodule Pleroma.EctoType.Config.Atom do def cast(_), do: :error + # A key or group naming a module that no longer exists (e.g. a removed uploader) + # must not crash loading def load(key) do {:ok, Pleroma.ConfigDB.string_to_elixir_types(key)} + rescue + ArgumentError -> + Logger.warning( + "ConfigDB: unknown module #{key} in a setting key or group, the setting is not applied" + ) + + {:ok, :invalid_atom} end def dump(key) when is_atom(key), do: {:ok, inspect(key)} diff --git a/test/pleroma/config/transfer_task_test.exs b/test/pleroma/config/transfer_task_test.exs index ea5378ffd..2f39712e3 100644 --- a/test/pleroma/config/transfer_task_test.exs +++ b/test/pleroma/config/transfer_task_test.exs @@ -96,6 +96,29 @@ defmodule Pleroma.Config.TransferTaskTest do assert Application.get_env(:pleroma, Pleroma.Search.ParadeDB.Repo)[:pool_size] == 2 end + test "skips settings with an unknown module key" do + now = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second) + + Repo.insert_all("config", [ + %{ + group: ":pleroma", + key: "Pleroma.Nowhere.Module", + value: :erlang.term_to_binary(enabled: true), + inserted_at: now, + updated_at: now + } + ]) + + insert(:config, key: :test_key, value: [live: 2]) + on_exit(fn -> Application.delete_env(:pleroma, :test_key) end) + + log = capture_log(fn -> assert :ok = TransferTask.load_and_update_env([], false) end) + + assert log =~ "Pleroma.Nowhere.Module" + assert Application.get_env(:pleroma, :test_key) == [live: 2] + refute Application.get_env(:pleroma, :invalid_atom) + end + describe "pleroma restart" do setup do on_exit(fn -> diff --git a/test/pleroma/config_db_test.exs b/test/pleroma/config_db_test.exs index ae17a9d34..43aca06c2 100644 --- a/test/pleroma/config_db_test.exs +++ b/test/pleroma/config_db_test.exs @@ -50,6 +50,22 @@ defmodule Pleroma.ConfigDBTest do assert config[:pleroma][:instance] == [name: "Pleroma"] end + test "loads a row with an unknown module key as :invalid_atom" do + now = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second) + + Repo.insert_all("config", [ + %{ + group: ":pleroma", + key: "Pleroma.Nowhere.Module", + value: :erlang.term_to_binary(enabled: true), + inserted_at: now, + updated_at: now + } + ]) + + assert [%ConfigDB{group: :pleroma, key: :invalid_atom}] = Repo.all(ConfigDB) + end + describe "update_or_create/1" do test "common" do config = insert(:config) diff --git a/test/pleroma/web/admin_api/controllers/config_controller_test.exs b/test/pleroma/web/admin_api/controllers/config_controller_test.exs index e4c8d866f..a035d558f 100644 --- a/test/pleroma/web/admin_api/controllers/config_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/config_controller_test.exs @@ -60,6 +60,28 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do assert key2 == inspect(config2.key) end + test "does not crash on a setting with an unknown module key", %{conn: conn} do + now = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second) + + Pleroma.Repo.insert_all("config", [ + %{ + group: ":pleroma", + key: "Pleroma.Nowhere.Module", + value: :erlang.term_to_binary(enabled: true), + inserted_at: now, + updated_at: now + } + ]) + + capture_log(fn -> + for path <- ["/api/pleroma/admin/config", "/api/pleroma/admin/config?only_db=true"] do + conn + |> get(path) + |> json_response_and_validate_schema(200) + end + end) + end + test "db is added to settings that are in db", %{conn: conn} do _config = insert(:config, key: ":instance", value: [name: "Some name"])