logo

pleroma

My custom branche(s) on git.pleroma.social/pleroma/pleroma
commit: 0fe36b311c010f9a4bd3c1600ce874c5403a7368
parent: 2ce141fb0e0b525ba9e869f258ff843cde3b29b3
Author: rinpatch <rinpatch@sdf.org>
Date:   Wed, 15 Jul 2020 14:00:22 +0000

Merge branch 'features/mrf-reasons' into 'develop'

Add rejection reason to our MRFs

See merge request pleroma/pleroma!2759

Diffstat:

Mlib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex2+-
Mlib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex7+++----
Mlib/pleroma/web/activity_pub/mrf/hellthread_policy.ex4++--
Mlib/pleroma/web/activity_pub/mrf/keyword_policy.ex7++++---
Mlib/pleroma/web/activity_pub/mrf/mention_policy.ex5+++--
Mlib/pleroma/web/activity_pub/mrf/object_age_policy.ex8+++-----
Mlib/pleroma/web/activity_pub/mrf/reject_non_public.ex2+-
Mlib/pleroma/web/activity_pub/mrf/simple_policy.ex16++++++++++------
Mlib/pleroma/web/activity_pub/mrf/tag_policy.ex7++++---
Mlib/pleroma/web/activity_pub/mrf/user_allow_list_policy.ex2+-
Mlib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex18+++++++++++-------
Mlib/pleroma/web/mastodon_api/controllers/status_controller.ex5+++++
Mtest/web/activity_pub/mrf/anti_followbot_policy_test.exs4++--
Mtest/web/activity_pub/mrf/hellthread_policy_test.exs3++-
Mtest/web/activity_pub/mrf/keyword_policy_test.exs12++++++++----
Mtest/web/activity_pub/mrf/mention_policy_test.exs6++++--
Mtest/web/activity_pub/mrf/reject_non_public_test.exs4++--
Mtest/web/activity_pub/mrf/simple_policy_test.exs16++++++++--------
Mtest/web/activity_pub/mrf/tag_policy_test.exs6+++---
Mtest/web/activity_pub/mrf/user_allowlist_policy_test.exs2+-
Mtest/web/activity_pub/mrf/vocabulary_policy_test.exs8++++----
Mtest/web/mastodon_api/controllers/status_controller_test.exs13+++++++++++++
22 files changed, 95 insertions(+), 62 deletions(-)

diff --git a/lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex b/lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex @@ -60,7 +60,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicy do if score < 0.8 do {:ok, message} else - {:reject, nil} + {:reject, "[AntiFollowbotPolicy] Scored #{actor_id} as #{score}"} end end diff --git a/lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex b/lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex @@ -39,14 +39,13 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy do {:ok, message} {:old_user, false} -> - {:reject, nil} + {:reject, "[AntiLinkSpamPolicy] User has no posts nor followers"} {:error, _} -> - {:reject, nil} + {:reject, "[AntiLinkSpamPolicy] Failed to get or fetch user by ap_id"} e -> - Logger.warn("[MRF anti-link-spam] WTF: unhandled error #{inspect(e)}") - {:reject, nil} + {:reject, "[AntiLinkSpamPolicy] Unhandled error #{inspect(e)}"} end end diff --git a/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex b/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex @@ -43,7 +43,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicy do defp reject_message(message, threshold) when threshold > 0 do with {_, recipients} <- get_recipient_count(message) do if recipients > threshold do - {:reject, nil} + {:reject, "[HellthreadPolicy] #{recipients} recipients is over the limit of #{threshold}"} else {:ok, message} end @@ -87,7 +87,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicy do {:ok, message} <- delist_message(message, delist_threshold) do {:ok, message} else - _e -> {:reject, nil} + e -> e end end diff --git a/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex b/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex @@ -24,7 +24,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do if Enum.any?(Pleroma.Config.get([:mrf_keyword, :reject]), fn pattern -> string_matches?(content, pattern) or string_matches?(summary, pattern) end) do - {:reject, nil} + {:reject, "[KeywordPolicy] Matches with rejected keyword"} else {:ok, message} end @@ -89,8 +89,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do {:ok, message} <- check_replace(message) do {:ok, message} else - _e -> - {:reject, nil} + {:reject, nil} -> {:reject, "[KeywordPolicy] "} + {:reject, _} = e -> e + _e -> {:reject, "[KeywordPolicy] "} end end diff --git a/lib/pleroma/web/activity_pub/mrf/mention_policy.ex b/lib/pleroma/web/activity_pub/mrf/mention_policy.ex @@ -12,8 +12,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicy do reject_actors = Pleroma.Config.get([:mrf_mention, :actors], []) recipients = (message["to"] || []) ++ (message["cc"] || []) - if Enum.any?(recipients, fn recipient -> Enum.member?(reject_actors, recipient) end) do - {:reject, nil} + if rejected_mention = + Enum.find(recipients, fn recipient -> Enum.member?(reject_actors, recipient) end) do + {:reject, "[MentionPolicy] Rejected for mention of #{rejected_mention}"} else {:ok, message} end diff --git a/lib/pleroma/web/activity_pub/mrf/object_age_policy.ex b/lib/pleroma/web/activity_pub/mrf/object_age_policy.ex @@ -28,7 +28,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy do defp check_reject(message, actions) do if :reject in actions do - {:reject, nil} + {:reject, "[ObjectAgePolicy]"} else {:ok, message} end @@ -47,9 +47,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy do {:ok, message} else - # Unhandleable error: somebody is messing around, just drop the message. _e -> - {:reject, nil} + {:reject, "[ObjectAgePolicy] Unhandled error"} end else {:ok, message} @@ -69,9 +68,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy do {:ok, message} else - # Unhandleable error: somebody is messing around, just drop the message. _e -> - {:reject, nil} + {:reject, "[ObjectAgePolicy] Unhandled error"} end else {:ok, message} diff --git a/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex b/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex @@ -38,7 +38,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublic do {:ok, object} true -> - {:reject, nil} + {:reject, "[RejectNonPublic] visibility: #{visibility}"} end end diff --git a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex @@ -21,7 +21,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do accepts == [] -> {:ok, object} actor_host == Config.get([Pleroma.Web.Endpoint, :url, :host]) -> {:ok, object} MRF.subdomain_match?(accepts, actor_host) -> {:ok, object} - true -> {:reject, nil} + true -> {:reject, "[SimplePolicy] host not in accept list"} end end @@ -31,7 +31,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do |> MRF.subdomains_regex() if MRF.subdomain_match?(rejects, actor_host) do - {:reject, nil} + {:reject, "[SimplePolicy] host in reject list"} else {:ok, object} end @@ -114,7 +114,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do |> MRF.subdomains_regex() if MRF.subdomain_match?(report_removal, actor_host) do - {:reject, nil} + {:reject, "[SimplePolicy] host in report_removal list"} else {:ok, object} end @@ -159,7 +159,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do |> MRF.subdomains_regex() if MRF.subdomain_match?(reject_deletes, actor_host) do - {:reject, nil} + {:reject, "[SimplePolicy] host in reject_deletes list"} else {:ok, object} end @@ -177,7 +177,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do {:ok, object} <- check_report_removal(actor_info, object) do {:ok, object} else - _e -> {:reject, nil} + {:reject, nil} -> {:reject, "[SimplePolicy]"} + {:reject, _} = e -> e + _ -> {:reject, "[SimplePolicy]"} end end @@ -191,7 +193,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do {:ok, object} <- check_banner_removal(actor_info, object) do {:ok, object} else - _e -> {:reject, nil} + {:reject, nil} -> {:reject, "[SimplePolicy]"} + {:reject, _} = e -> e + _ -> {:reject, "[SimplePolicy]"} end end diff --git a/lib/pleroma/web/activity_pub/mrf/tag_policy.ex b/lib/pleroma/web/activity_pub/mrf/tag_policy.ex @@ -134,12 +134,13 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do if user.local == true do {:ok, message} else - {:reject, nil} + {:reject, + "[TagPolicy] Follow from #{actor} tagged with mrf_tag:disable-remote-subscription"} end end - defp process_tag("mrf_tag:disable-any-subscription", %{"type" => "Follow"}), - do: {:reject, nil} + defp process_tag("mrf_tag:disable-any-subscription", %{"type" => "Follow", "actor" => actor}), + do: {:reject, "[TagPolicy] Follow from #{actor} tagged with mrf_tag:disable-any-subscription"} defp process_tag(_, message), do: {:ok, message} diff --git a/lib/pleroma/web/activity_pub/mrf/user_allow_list_policy.ex b/lib/pleroma/web/activity_pub/mrf/user_allow_list_policy.ex @@ -14,7 +14,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.UserAllowListPolicy do if actor in allow_list do {:ok, object} else - {:reject, nil} + {:reject, "[UserAllowListPolicy] #{actor} not in the list"} end end diff --git a/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex b/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex @@ -11,22 +11,26 @@ defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicy do with {:ok, _} <- filter(child_message) do {:ok, message} else - {:reject, nil} -> - {:reject, nil} + {:reject, _} = e -> e end end def filter(%{"type" => message_type} = message) do with accepted_vocabulary <- Pleroma.Config.get([:mrf_vocabulary, :accept]), rejected_vocabulary <- Pleroma.Config.get([:mrf_vocabulary, :reject]), - true <- - Enum.empty?(accepted_vocabulary) || Enum.member?(accepted_vocabulary, message_type), - false <- - length(rejected_vocabulary) > 0 && Enum.member?(rejected_vocabulary, message_type), + {_, true} <- + {:accepted, + Enum.empty?(accepted_vocabulary) || Enum.member?(accepted_vocabulary, message_type)}, + {_, false} <- + {:rejected, + length(rejected_vocabulary) > 0 && Enum.member?(rejected_vocabulary, message_type)}, {:ok, _} <- filter(message["object"]) do {:ok, message} else - _ -> {:reject, nil} + {:reject, _} = e -> e + {:accepted, _} -> {:reject, "[VocabularyPolicy] #{message_type} not in accept list"} + {:rejected, _} -> {:reject, "[VocabularyPolicy] #{message_type} in reject list"} + _ -> {:reject, "[VocabularyPolicy]"} end end diff --git a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex @@ -172,6 +172,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do with_direct_conversation_id: true ) else + {:error, {:reject, message}} -> + conn + |> put_status(:unprocessable_entity) + |> json(%{error: message}) + {:error, message} -> conn |> put_status(:unprocessable_entity) diff --git a/test/web/activity_pub/mrf/anti_followbot_policy_test.exs b/test/web/activity_pub/mrf/anti_followbot_policy_test.exs @@ -21,7 +21,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicyTest do "id" => "https://example.com/activities/1234" } - {:reject, nil} = AntiFollowbotPolicy.filter(message) + assert {:reject, "[AntiFollowbotPolicy]" <> _} = AntiFollowbotPolicy.filter(message) end test "matches followbots by display name" do @@ -36,7 +36,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicyTest do "id" => "https://example.com/activities/1234" } - {:reject, nil} = AntiFollowbotPolicy.filter(message) + assert {:reject, "[AntiFollowbotPolicy]" <> _} = AntiFollowbotPolicy.filter(message) end end diff --git a/test/web/activity_pub/mrf/hellthread_policy_test.exs b/test/web/activity_pub/mrf/hellthread_policy_test.exs @@ -50,7 +50,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicyTest do } do Pleroma.Config.put([:mrf_hellthread], %{delist_threshold: 0, reject_threshold: 2}) - {:reject, nil} = filter(message) + assert {:reject, "[HellthreadPolicy] 3 recipients is over the limit of 2"} == + filter(message) end test "does not reject the message if the recipient count is below reject_threshold", %{ diff --git a/test/web/activity_pub/mrf/keyword_policy_test.exs b/test/web/activity_pub/mrf/keyword_policy_test.exs @@ -25,7 +25,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do } } - assert {:reject, nil} == KeywordPolicy.filter(message) + assert {:reject, "[KeywordPolicy] Matches with rejected keyword"} = + KeywordPolicy.filter(message) end test "rejects if string matches in summary" do @@ -39,7 +40,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do } } - assert {:reject, nil} == KeywordPolicy.filter(message) + assert {:reject, "[KeywordPolicy] Matches with rejected keyword"} = + KeywordPolicy.filter(message) end test "rejects if regex matches in content" do @@ -55,7 +57,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do } } - {:reject, nil} == KeywordPolicy.filter(message) + {:reject, "[KeywordPolicy] Matches with rejected keyword"} == + KeywordPolicy.filter(message) end) end @@ -72,7 +75,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do } } - {:reject, nil} == KeywordPolicy.filter(message) + {:reject, "[KeywordPolicy] Matches with rejected keyword"} == + KeywordPolicy.filter(message) end) end end diff --git a/test/web/activity_pub/mrf/mention_policy_test.exs b/test/web/activity_pub/mrf/mention_policy_test.exs @@ -76,7 +76,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicyTest do "to" => ["https://example.com/blocked"] } - assert MentionPolicy.filter(message) == {:reject, nil} + assert MentionPolicy.filter(message) == + {:reject, "[MentionPolicy] Rejected for mention of https://example.com/blocked"} end test "cc" do @@ -88,7 +89,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicyTest do "cc" => ["https://example.com/blocked"] } - assert MentionPolicy.filter(message) == {:reject, nil} + assert MentionPolicy.filter(message) == + {:reject, "[MentionPolicy] Rejected for mention of https://example.com/blocked"} end end end diff --git a/test/web/activity_pub/mrf/reject_non_public_test.exs b/test/web/activity_pub/mrf/reject_non_public_test.exs @@ -64,7 +64,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublicTest do } Pleroma.Config.put([:mrf_rejectnonpublic, :allow_followersonly], false) - assert {:reject, nil} = RejectNonPublic.filter(message) + assert {:reject, _} = RejectNonPublic.filter(message) end end @@ -94,7 +94,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublicTest do } Pleroma.Config.put([:mrf_rejectnonpublic, :allow_direct], false) - assert {:reject, nil} = RejectNonPublic.filter(message) + assert {:reject, _} = RejectNonPublic.filter(message) end end end diff --git a/test/web/activity_pub/mrf/simple_policy_test.exs b/test/web/activity_pub/mrf/simple_policy_test.exs @@ -124,7 +124,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do report_message = build_report_message() local_message = build_local_message() - assert SimplePolicy.filter(report_message) == {:reject, nil} + assert {:reject, _} = SimplePolicy.filter(report_message) assert SimplePolicy.filter(local_message) == {:ok, local_message} end @@ -133,7 +133,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do report_message = build_report_message() local_message = build_local_message() - assert SimplePolicy.filter(report_message) == {:reject, nil} + assert {:reject, _} = SimplePolicy.filter(report_message) assert SimplePolicy.filter(local_message) == {:ok, local_message} end end @@ -241,7 +241,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do remote_message = build_remote_message() - assert SimplePolicy.filter(remote_message) == {:reject, nil} + assert {:reject, _} = SimplePolicy.filter(remote_message) end test "activity matches with wildcard domain" do @@ -249,7 +249,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do remote_message = build_remote_message() - assert SimplePolicy.filter(remote_message) == {:reject, nil} + assert {:reject, _} = SimplePolicy.filter(remote_message) end test "actor has a matching host" do @@ -257,7 +257,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do remote_user = build_remote_user() - assert SimplePolicy.filter(remote_user) == {:reject, nil} + assert {:reject, _} = SimplePolicy.filter(remote_user) end end @@ -279,7 +279,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do remote_message = build_remote_message() assert SimplePolicy.filter(local_message) == {:ok, local_message} - assert SimplePolicy.filter(remote_message) == {:reject, nil} + assert {:reject, _} = SimplePolicy.filter(remote_message) end test "activity has a matching host" do @@ -429,7 +429,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do test "it rejects the deletion" do deletion_message = build_remote_deletion_message() - assert SimplePolicy.filter(deletion_message) == {:reject, nil} + assert {:reject, _} = SimplePolicy.filter(deletion_message) end end @@ -439,7 +439,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do test "it rejects the deletion" do deletion_message = build_remote_deletion_message() - assert SimplePolicy.filter(deletion_message) == {:reject, nil} + assert {:reject, _} = SimplePolicy.filter(deletion_message) end end diff --git a/test/web/activity_pub/mrf/tag_policy_test.exs b/test/web/activity_pub/mrf/tag_policy_test.exs @@ -12,8 +12,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicyTest do describe "mrf_tag:disable-any-subscription" do test "rejects message" do actor = insert(:user, tags: ["mrf_tag:disable-any-subscription"]) - message = %{"object" => actor.ap_id, "type" => "Follow"} - assert {:reject, nil} = TagPolicy.filter(message) + message = %{"object" => actor.ap_id, "type" => "Follow", "actor" => actor.ap_id} + assert {:reject, _} = TagPolicy.filter(message) end end @@ -22,7 +22,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicyTest do actor = insert(:user, tags: ["mrf_tag:disable-remote-subscription"]) follower = insert(:user, tags: ["mrf_tag:disable-remote-subscription"], local: false) message = %{"object" => actor.ap_id, "type" => "Follow", "actor" => follower.ap_id} - assert {:reject, nil} = TagPolicy.filter(message) + assert {:reject, _} = TagPolicy.filter(message) end test "allows non-local follow requests" do diff --git a/test/web/activity_pub/mrf/user_allowlist_policy_test.exs b/test/web/activity_pub/mrf/user_allowlist_policy_test.exs @@ -26,6 +26,6 @@ defmodule Pleroma.Web.ActivityPub.MRF.UserAllowListPolicyTest do actor = insert(:user) Pleroma.Config.put([:mrf_user_allowlist], %{"localhost" => ["test-ap-id"]}) message = %{"actor" => actor.ap_id} - assert UserAllowListPolicy.filter(message) == {:reject, nil} + assert {:reject, _} = UserAllowListPolicy.filter(message) end end diff --git a/test/web/activity_pub/mrf/vocabulary_policy_test.exs b/test/web/activity_pub/mrf/vocabulary_policy_test.exs @@ -46,7 +46,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicyTest do } } - {:reject, nil} = VocabularyPolicy.filter(message) + {:reject, _} = VocabularyPolicy.filter(message) end test "it does not accept disallowed parent types" do @@ -60,7 +60,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicyTest do } } - {:reject, nil} = VocabularyPolicy.filter(message) + {:reject, _} = VocabularyPolicy.filter(message) end end @@ -75,7 +75,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicyTest do "object" => "whatever" } - {:reject, nil} = VocabularyPolicy.filter(message) + {:reject, _} = VocabularyPolicy.filter(message) end test "it rejects based on child object type" do @@ -89,7 +89,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicyTest do } } - {:reject, nil} = VocabularyPolicy.filter(message) + {:reject, _} = VocabularyPolicy.filter(message) end test "it passes through objects that aren't disallowed" do diff --git a/test/web/mastodon_api/controllers/status_controller_test.exs b/test/web/mastodon_api/controllers/status_controller_test.exs @@ -22,6 +22,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do setup do: clear_config([:instance, :federating]) setup do: clear_config([:instance, :allow_relay]) setup do: clear_config([:rich_media, :enabled]) + setup do: clear_config([:mrf, :policies]) + setup do: clear_config([:mrf_keyword, :reject]) describe "posting statuses" do setup do: oauth_access(["write:statuses"]) @@ -157,6 +159,17 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do |> json_response_and_validate_schema(422) end + test "Get MRF reason when posting a status is rejected by one", %{conn: conn} do + Pleroma.Config.put([:mrf_keyword, :reject], ["GNO"]) + Pleroma.Config.put([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.KeywordPolicy]) + + assert %{"error" => "[KeywordPolicy] Matches with rejected keyword"} = + conn + |> put_req_header("content-type", "application/json") + |> post("api/v1/statuses", %{"status" => "GNO/Linux"}) + |> json_response_and_validate_schema(422) + end + test "posting an undefined status with an attachment", %{user: user, conn: conn} do file = %Plug.Upload{ content_type: "image/jpg",