fix(config): skip ConfigDB settings for modules that no longer exist

Ported from Akkoma af7c3fab9; the rescue is in the Ecto type load so
admin input is still validated.

Co-authored-by: FloatingGhost <hannah@coffee-and-dreams.uk>
This commit is contained in:
Lain Soykaf 2026-10-31 13:43:59 +04:00
commit 88a9562a9b
No known key found for this signature in database
6 changed files with 74 additions and 0 deletions

View file

@ -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

View file

@ -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()

View file

@ -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)}

View file

@ -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 ->

View file

@ -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)

View file

@ -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"])