T11: Mastodon 4.7.3 in the pasture

peers/mastodon.sh runs Mastodon's web and sidekiq containers on a shared Postgres and Redis
(peers/shared.sh). They trust Caddy's CA through SSL_CERT_FILE and reach private addresses
through ALLOWED_PRIVATE_ADDRESSES. Its users and tokens come from tootctl and rails runner.

scenarios/mastodon.sh adds 49 checks, as listed in docs/INTEROP.md: follows, posts,
replies, likes and boosts with undos, DMs, polls, FEP-044f quotes both ways, media through
the proxy, edits, deletes, locked follows, a circle request, reports, blocks and statistics.
Two are expected failures:
- inbound Block (P7);
- circle posts. Mastodon 4.7 loses the recipient of deliveries to its numeric
  /ap/users/<id>/inbox and then drops a post that names no local account. The fix on our
  side changes what a circle reveals, so it waits for the owner.

GoToSocial and Mastodon together: 86 passed, 0 failed.

The pasture now copies Caddy's root certificate reliably, readable by the peers, and
rebuilds the bundle each time. The CA directory is mounted shared (:z), because a private
:Z label locks out every container but the last. pfetch reaches PrivaPub's own https URIs
through Caddy. PRIVAPUB_ENV passes settings to PrivaPub, which scenarios/crawler.sh uses to
check the opt-in crawler against Mastodon: it visits, describes and reads the peers list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ELjqpznMFMNrJoJUj6K5p2
This commit is contained in:
thepraandClaude Opus 5.5 committed 2026-10-03 12:30:05 +02:00
1 parent d0a13d9cc2
commit e0f2eb7da7
9 files changed
+367 -28

No files matched your search

+56
View File
@@ -0,0 +1,56 @@
# Mastodon: web (puma) and sidekiq from one image, on the shared Postgres and Redis. Streaming is not needed.
MASTODON_IMAGE=ghcr.io/mastodon/mastodon:v4.7.3
. "$here/peers/shared.sh"
mastodon_env() {
cat <<ENV
LOCAL_DOMAIN=mastodon.test
RAILS_ENV=production
NODE_ENV=production
DB_HOST=postgres
DB_USER=pasture
DB_PASS=pasture
DB_NAME=mastodon
REDIS_URL=redis://redis:6379/1
SECRET_KEY_BASE=pasture0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
OTP_SECRET=pasture000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=pasturedeterministickey0000000000
ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=pasturederivationsalt000000000000
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=pastureprimarykey0000000000000000
ALLOWED_PRIVATE_ADDRESSES=10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
SSL_CERT_FILE=/pasture/ca/bundle.pem
SKIP_POST_DEPLOYMENT_MIGRATIONS=false
WEB_CONCURRENCY=0
MAX_THREADS=8
RAILS_LOG_LEVEL=warn
${MASTODON_EXTRA_ENV:-}
ENV
}
mastodon_up() {
shared_postgres_up
shared_redis_up
mastodon_env > "$here/.ca/mastodon.env"
local common=(--network $net --env-file "$here/.ca/mastodon.env" -v "$ca:/pasture/ca:z,ro")
podman run --rm "${common[@]}" -e SAFETY_ASSURED=1 $MASTODON_IMAGE bundle exec rails db:prepare >/dev/null
podman run -d --replace --name pasture-mastodon "${common[@]}" -p 127.0.0.1:6973:3000 $MASTODON_IMAGE bundle exec puma -C config/puma.rb >/dev/null
podman run -d --replace --name pasture-mastodon-sidekiq "${common[@]}" $MASTODON_IMAGE bundle exec sidekiq >/dev/null
wait_http http://127.0.0.1:6973/health 90
podman exec pasture-mastodon bin/tootctl accounts create mastouser --email mastouser@mastodon.test --confirmed --role Owner >/dev/null 2>&1 || true
podman exec pasture-mastodon bin/tootctl accounts approve mastouser >/dev/null 2>&1 || true
echo "mastodon: https://mastodon.test:6443"
}
# mastodon_token [user]: a token for a Mastodon user, made directly (Mastodon offers no password grant). Owners get
# admin:read too, for reading reports.
mastodon_token() {
podman exec pasture-mastodon bin/rails runner '
app = Doorkeeper::Application.find_or_create_by!(name: "pasture") { |a| a.redirect_uri = "urn:ietf:wg:oauth:2.0:oob"; a.scopes = "read write follow admin:read" }
user = Account.find_local("'"${1:-mastouser}"'").user
puts Doorkeeper::AccessToken.create!(application_id: app.id, resource_owner_id: user.id, scopes: "read write follow admin:read").token' 2>/dev/null | tail -1
}
mastodon_user() { # name
podman exec pasture-mastodon bin/tootctl accounts create "$1" --email "$1@mastodon.test" --confirmed >/dev/null 2>&1 || true
podman exec pasture-mastodon bin/tootctl accounts approve "$1" >/dev/null 2>&1 || true
}