Files
SocialPub/tools/pasture/sweep.sh
T
thepraandClaude Opus 5.5 9f68ca3ed0 R6 moderation: roles, silence and suspension, bans that write nothing on the personas, deletions, report actions
Roles (user, moderator, administrator) from the CLI and /clientapi/admin/roots/{id}/role, never one's own nor the last
administrator. Silence keeps an account's posts out of public timelines, hashtags, trends, search and relays while its
followers still get them; suspension refuses and revokes a local persona's tokens, answers 404 for its posts and
collections, holds back every delivery and tells other servers nothing new, its actor unchanged; a suspended remote
account's activities are dropped and nothing goes to its own inbox (a shared one still serves its server). A banned
login's personas are held back in memory alone (Restrictions), so nothing pairs them in stored data. Personas and groups
are deleted one at a time (PersonaRemoval, GroupRemoval), by their login or an administrator with the password. Reports
resolve with an action and a note; posts are taken down, a remote copy hidden. Warnings reach the persona as Mastodon's
moderation_warning. Every staff act goes to the staff's log. Migration _020 limits posts from servers already silenced;
a restore keeps the moderation made since the backup.

Verified: interop.sh moderation gts mastodon with SecureMode, 194 passed; restore.sh, 25 passed, now with a suspension,
a silence and a takedown made after the backup.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WpVCoDeM1qUTRp4fXQdfof
2026-10-17 05:23:45 +02:00

75 lines
3.6 KiB
Bash
Executable File

#!/usr/bin/env bash
# Every peer's scenario, a batch of peers at a time: a change to what PrivaPub sends (the @context, an actor's
# properties, an activity's shape, a delivery's headers) runs against all of them before it is committed, since one
# reader stricter than the rest fails on it alone. Each batch starts its own pasture afresh (run.sh up), runs its
# scenarios (interop.sh) and takes the pasture down (run.sh down), and the next batch runs whatever the one before did.
# PrivaPub runs with SecureMode on, as in production, unless PRIVAPUB_ENV says otherwise; DOTNET and PASTURE_PORT reach
# run.sh as they are. Each batch's output is kept in out/sweep-<batch>.log.
# usage: tools/pasture/sweep.sh [A|B|C|D ...] (default: every batch, in that order)
# A gts mastodon misskey sharkey akkoma, with relay, aoderelay and mailpit; scenarios: those five, threads followsync
# pins moves relay (relay's covers both relays) accounts (mailpit's) instance (the server's own settings: it changes
# them all and puts them back) moderation (gts and mastodon; after instance, whose log check expects only the
# administrator's acts)
# B lemmy lemmy19 piefed mbin nodebb
# C peertube pixelfed vernissage wordpress ghost writefreely owncast castopod funkwhale
# D friendica mobilizon gancio bookwyrm smithereen mitra snac ktistec forte hubzilla
# Not swept: restore (run it alone: it restores the whole server), crawler (it needs the crawler's own settings) and
# persona-archive; hollo, iceshrimp, pleroma, flood and decepub have no scenario of their own.
set -uo pipefail
here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
export PRIVAPUB_ENV=${PRIVAPUB_ENV:-Federation__SecureMode=true}
batch_peers() {
case "$1" in
A) echo "gts mastodon misskey sharkey akkoma relay aoderelay mailpit" ;;
B) echo "lemmy lemmy19 piefed mbin nodebb" ;;
C) echo "peertube pixelfed vernissage wordpress ghost writefreely owncast castopod funkwhale" ;;
D) echo "friendica mobilizon gancio bookwyrm smithereen mitra snac ktistec forte hubzilla" ;;
esac
}
batch_scenarios() {
case "$1" in
A) echo "gts mastodon misskey sharkey akkoma threads followsync pins moves relay accounts instance moderation" ;;
*) batch_peers "$1" ;;
esac
}
[ $# -gt 0 ] || set -- A B C D
for batch in "$@"; do
[ -n "$(batch_peers "$batch")" ] || { echo "no such batch: $batch (A, B, C or D)" >&2; exit 2; }
for peer in $(batch_peers "$batch"); do
[ -f "$here/peers/$peer.sh" ] || { echo "batch $batch: no such peer: $peer" >&2; exit 2; }
done
for scenario in $(batch_scenarios "$batch"); do
[ -f "$here/scenarios/$scenario.sh" ] || { echo "batch $batch: no scenario for $scenario" >&2; exit 2; }
done
done
mkdir -p "$here/out"
summary=(); bad=0
for batch in "$@"; do
log="$here/out/sweep-$batch.log"
echo "== batch $batch: $(batch_peers "$batch")"
# shellcheck disable=SC2046
if ! "$here/run.sh" up $(batch_peers "$batch") 2>&1 | tee "$log"; then
summary+=("$batch the pasture did not start (out/sweep-$batch.log)"); bad=1
"$here/run.sh" down || true
continue
fi
# shellcheck disable=SC2046
"$here/interop.sh" $(batch_scenarios "$batch") 2>&1 | tee -a "$log"
status=${PIPESTATUS[0]}
"$here/run.sh" down || true
passed=$(grep -c '^ ok ' "$log"); failed=$(grep -c '^ FAIL ' "$log"); xfailed=$(grep -c '^ xf ' "$log")
line="$batch ok $passed ko $failed xf $xfailed ($(batch_scenarios "$batch"))"
if ! grep -qE '^[0-9]+ passed, [0-9]+ failed, [0-9]+ expected failures$' "$log"; then
line="$line stopped before its end (exit $status)"; bad=1
fi
[ "$failed" = 0 ] || bad=1
summary+=("$line")
done
echo; echo "sweep:"
printf ' %s\n' "${summary[@]}"
[ "$bad" = 0 ]