From 04fbb59932e497cbab6891f4dc664f1ed47b5f02 Mon Sep 17 00:00:00 2001 From: Lain Soykaf Date: Tue, 27 Oct 2026 12:51:14 +0400 Subject: [PATCH] fix(federation): cancel queued deliveries to blocked instances Delivery jobs only checked reachability, so a job queued (or retrying) before the admin rejected or quarantined an instance was still sent. Check should_federate? again when the job runs. --- lib/pleroma/workers/publisher_worker.ex | 49 ++++++++++++------- .../pleroma/workers/publisher_worker_test.exs | 34 +++++++++++++ 2 files changed, 66 insertions(+), 17 deletions(-) diff --git a/lib/pleroma/workers/publisher_worker.ex b/lib/pleroma/workers/publisher_worker.ex index 186f6f4ef..7bd00aad8 100644 --- a/lib/pleroma/workers/publisher_worker.ex +++ b/lib/pleroma/workers/publisher_worker.ex @@ -6,6 +6,8 @@ defmodule Pleroma.Workers.PublisherWorker do alias Pleroma.Activity alias Pleroma.Config alias Pleroma.Instances + alias Pleroma.Web.ActivityPub.Publisher + alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.Federator use Oban.Worker, queue: :federator_outgoing, max_attempts: 13 @@ -32,26 +34,39 @@ defmodule Pleroma.Workers.PublisherWorker do end end) - # Cancel / skip the job if this server believed to be unreachable now - if not Instances.reachable?(params.inbox) do - {:cancel, :unreachable} - else - case federator().perform(:publish_one, params) do - {:ok, _} -> - :ok + cond do + # Cancel / skip the job if this server believed to be unreachable now + not Instances.reachable?(params.inbox) -> + {:cancel, :unreachable} - {:error, _} = error -> - # Only mark as unreachable on final failure - if job.attempt == job.max_attempts do - Instances.set_unreachable(params.inbox) - end + # The instance may have been blocked after the job was queued + not federate?(params) -> + {:cancel, :rejected} - error + true -> + case federator().perform(:publish_one, params) do + {:ok, _} -> + :ok - error -> - # Unexpected error, may have been client side - error - end + {:error, _} = error -> + # Only mark as unreachable on final failure + if job.attempt == job.max_attempts do + Instances.set_unreachable(params.inbox) + end + + error + + error -> + # Unexpected error, may have been client side + error + end + end + end + + defp federate?(%{inbox: inbox, activity_id: activity_id}) do + case Activity.get_by_id(activity_id) do + %Activity{} = activity -> Publisher.should_federate?(inbox, Visibility.public?(activity)) + nil -> true end end diff --git a/test/pleroma/workers/publisher_worker_test.exs b/test/pleroma/workers/publisher_worker_test.exs index ddbbba910..4ee0772e0 100644 --- a/test/pleroma/workers/publisher_worker_test.exs +++ b/test/pleroma/workers/publisher_worker_test.exs @@ -153,4 +153,38 @@ defmodule Pleroma.Workers.PublisherWorkerTest do assert {:cancel, :unreachable} = PublisherWorker.perform(job) end end + + describe "Blocked instances:" do + defp publish_one_job(inbox, activity) do + %Oban.Job{ + args: %{ + "op" => "publish_one", + "params" => %{"inbox" => inbox, "activity_id" => activity.id} + }, + attempt: 1, + max_attempts: 5 + } + end + + test "cancels queued jobs to instances rejected by SimplePolicy" do + clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.SimplePolicy]) + clear_config([:mrf_simple, :reject], [{"rejected.example", ""}]) + {:ok, activity} = CommonAPI.post(insert(:user), %{status: "public"}) + + assert {:cancel, :rejected} = + PublisherWorker.perform( + publish_one_job("https://rejected.example/inbox", activity) + ) + end + + test "cancels queued private jobs to quarantined instances" do + clear_config([:instance, :quarantined_instances], [{"quarantined.example", ""}]) + {:ok, activity} = CommonAPI.post(insert(:user), %{status: "hi", visibility: "private"}) + + assert {:cancel, :rejected} = + PublisherWorker.perform( + publish_one_job("https://quarantined.example/inbox", activity) + ) + end + end end