Pasture: WordPress pinned with its updates off, Mbin's worker restarting, threads checking our own deliveries
A full sweep found three peers silent. WordPress had updated itself to 7.1.2 from WP-Cron, and the new CA bundle dropped Caddy's root: it now runs the 7.1.2 image with automatic updates off. Mbin's messenger worker had died when the shared Postgres restarted under it: it now consumes again whenever it stops. Friendica sat in a quarantine left by the old breaker. The threads scenario checks that PrivaPub never sends carol's reply to Mastodon, since a relay Mastodon has just left (the relay scenario's) may still pass it on. With these, every scenario passes but the crawler's, which needs it switched on. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
This commit is contained in:
1 parent
cb34ab88f7
commit
bebb4d6370
5 files changed
+26
-13
No files matched your search
@@ -548,7 +548,8 @@ tools/pasture/run.sh down # removes e
|
|||||||
communities both ways, threads with titles, comments, votes up and down both ways, a community poll and alice's vote,
|
communities both ways, threads with titles, comments, votes up and down both ways, a community poll and alice's vote,
|
||||||
private messages both ways, a moderator's lock, unlock and removal, the unfollow, statistics.
|
private messages both ways, a moderator's lock, unlock and removal, the unfollow, statistics.
|
||||||
- **Mbin (1.10.1):** its own image (FrankenPHP serving plain HTTP behind Caddy, `SERVER_NAME=:80`) and a messenger
|
- **Mbin (1.10.1):** its own image (FrankenPHP serving plain HTTP behind Caddy, `SERVER_NAME=:80`) and a messenger
|
||||||
worker, on the shared Postgres and Redis (db 12) with a RabbitMQ of its own (its transports carry AMQP options; it
|
worker (`mbin_worker`, consuming again whenever it stops: once, the shared Postgres restarted under it and Mbin sent
|
||||||
|
nothing for a day), on the shared Postgres and Redis (db 12) with a RabbitMQ of its own (its transports carry AMQP options; it
|
||||||
runs as its own user on its own volume, or it cannot read the `.erlang.cookie` it wrote as root). The pasture's bundle
|
runs as its own user on its own volume, or it cannot read the `.erlang.cookie` it wrote as root). The pasture's bundle
|
||||||
is mounted over the system one; its API's rate limits (two threads every six minutes) are raised by a copy of its
|
is mounted over the system one; its API's rate limits (two threads every six minutes) are raised by a copy of its
|
||||||
`rate_limiter.yaml`. Its admin mbuser is made by its console; `peers/mbin_token.py` gets mbuser's OAuth token through
|
`rate_limiter.yaml`. Its admin mbuser is made by its console; `peers/mbin_token.py` gets mbuser's OAuth token through
|
||||||
@@ -681,11 +682,13 @@ tools/pasture/run.sh down # removes e
|
|||||||
clients from a million (Passport refuses a token whose user id equals its client's id), and imports its cities.
|
clients from a million (Passport refuses a token whose user id equals its client's id), and imports its cities.
|
||||||
Tokens are personal access tokens made through tinker (`App\Models\User`). Every top-level post needs a picture.
|
Tokens are personal access tokens made through tinker (`App\Models\User`). Every top-level post needs a picture.
|
||||||
`scenarios/pixelfed.sh`, 26 checks; the town's driver and `specs/pixelfed-pair.json`.
|
`scenarios/pixelfed.sh`, 26 checks; the town's driver and `specs/pixelfed-pair.json`.
|
||||||
- **WordPress (6, ActivityPub plugin 9.3.1):** the official image on a shared MySQL 8.4 (`shared_mysql_up`, ready only
|
- **WordPress (7.1.2, ActivityPub plugin 9.3.1):** the official image on a shared MySQL 8.4 (`shared_mysql_up`, ready
|
||||||
when it answers over TCP: its first start runs a server without networking), installed and configured by wp-cli,
|
only when it answers over TCP: its first start runs a server without networking), installed and configured by wp-cli,
|
||||||
its CA bundle (`wp-includes/certificates/ca-bundle.crt`) given Caddy's root, and WP-Cron run every five seconds by a
|
its CA bundle (`wp-includes/certificates/ca-bundle.crt`) given Caddy's root, and WP-Cron run every five seconds by a
|
||||||
sidecar (`DISABLE_WP_CRON`), since the plugin federates from it. Authors are actors; the REST API takes application
|
sidecar (`DISABLE_WP_CRON`), since the plugin federates from it. Its automatic updates are off
|
||||||
passwords. `scenarios/wordpress.sh`, 17 checks.
|
(`AUTOMATIC_UPDATER_DISABLED`): the sidecar ran one (6 to 7.1.2) whose new CA bundle dropped Caddy's root, and
|
||||||
|
WordPress reached nobody after it. Authors are actors; the REST API takes application passwords.
|
||||||
|
`scenarios/wordpress.sh`, 17 checks.
|
||||||
- **Friendica (2026.05):** the official image on the shared MySQL (database friendica) and Redis (db 7, for its cache,
|
- **Friendica (2026.05):** the official image on the shared MySQL (database friendica) and Redis (db 7, for its cache,
|
||||||
locks and sessions), installed by its autoinstall, with the image's worker daemon (`cron.sh`) as a sidecar sharing
|
locks and sessions), installed by its autoinstall, with the image's worker daemon (`cron.sh`) as a sidecar sharing
|
||||||
its files. `friendica_settle` repairs what the install leaves: it names the system user (uid 0), or Friendica never
|
its files. `friendica_settle` repairs what the install leaves: it names the system user (uid 0), or Friendica never
|
||||||
|
|||||||
+1
-1
@@ -29,7 +29,7 @@ and every run starting clean, with signed fetches required (as privapub.thepra.d
|
|||||||
- **Lemmy 1.0.0-beta.2**, and **Lemmy 0.19.20** (built with the platform's roots, so it trusts the pasture's CA)
|
- **Lemmy 1.0.0-beta.2**, and **Lemmy 0.19.20** (built with the platform's roots, so it trusts the pasture's CA)
|
||||||
- **PeerTube 8.3.1**
|
- **PeerTube 8.3.1**
|
||||||
- **Pixelfed 0.14.4**
|
- **Pixelfed 0.14.4**
|
||||||
- **WordPress 6 with ActivityPub 9.3.1**
|
- **WordPress 7.1.2 with ActivityPub 9.3.1**
|
||||||
- **Friendica 2026.05**
|
- **Friendica 2026.05**
|
||||||
- **Mobilizon 5.2.4**
|
- **Mobilizon 5.2.4**
|
||||||
- **Gancio 1.28.2**
|
- **Gancio 1.28.2**
|
||||||
|
|||||||
@@ -82,8 +82,7 @@ mbin_up() {
|
|||||||
podman logs pasture-mbin 2>&1 | grep -q "PHP app ready" && break
|
podman logs pasture-mbin 2>&1 | grep -q "PHP app ready" && break
|
||||||
sleep 2
|
sleep 2
|
||||||
done
|
done
|
||||||
podman run -d --replace --name pasture-mbin-worker "${common[@]}" "$MBIN_IMAGE" \
|
mbin_worker
|
||||||
php bin/console messenger:consume scheduler_default old async outbox deliver inbox resolve receive failed --time-limit=86400 >/dev/null
|
|
||||||
for _ in $(seq 1 60); do
|
for _ in $(seq 1 60); do
|
||||||
site mbin.test -s -o /dev/null -w '%{http_code}' https://mbin.test:6443/api/instance 2>/dev/null | grep -q 200 && break
|
site mbin.test -s -o /dev/null -w '%{http_code}' https://mbin.test:6443/api/instance 2>/dev/null | grep -q 200 && break
|
||||||
sleep 2
|
sleep 2
|
||||||
@@ -102,3 +101,11 @@ mbin_settle() {
|
|||||||
mbin_console mbin:user:verify mbuser >/dev/null 2>&1 || true
|
mbin_console mbin:user:verify mbuser >/dev/null 2>&1 || true
|
||||||
python3 "$here/peers/mbin_token.py" "$MBIN_PASSWORD" "$here/.state/mbin/client.json" > "$here/.state/mbin.token" 2>"$here/.state/mbin/token.log" || true
|
python3 "$here/peers/mbin_token.py" "$MBIN_PASSWORD" "$here/.state/mbin/client.json" > "$here/.state/mbin.token" 2>"$here/.state/mbin/token.log" || true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# mbin_worker: the messenger worker, consuming again whenever it stops (an hour's time limit, or a lost database: a
|
||||||
|
# Postgres restarted once left Mbin sending nothing for a day)
|
||||||
|
mbin_worker() {
|
||||||
|
podman run -d --replace --name pasture-mbin-worker "${common[@]}" "$MBIN_IMAGE" sh -c 'while :; do
|
||||||
|
php bin/console messenger:consume scheduler_default old async outbox deliver inbox resolve receive failed --time-limit=3600; sleep 5
|
||||||
|
done' >/dev/null
|
||||||
|
}
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
# WordPress 6 with the ActivityPub plugin 9.3.1: posts as Articles (or Notes when short), comments as replies, each
|
# WordPress 7.1.2 with the ActivityPub plugin 9.3.1: posts as Articles (or Notes when short), comments as replies, each
|
||||||
# author an actor and the blog one too, likes and boosts kept as comments of their kind. On a shared MySQL 8.4 (database
|
# author an actor and the blog one too, likes and boosts kept as comments of their kind. On a shared MySQL 8.4 (database
|
||||||
# wordpress). The plugin federates from WP-Cron, so a sidecar runs the due events every few seconds. WordPress sends its
|
# wordpress). The plugin federates from WP-Cron, so a sidecar runs the due events every few seconds. WordPress sends its
|
||||||
# requests through its own CA bundle (wp-includes/certificates), to which Caddy's root is appended; its URL guard refuses
|
# requests through its own CA bundle (wp-includes/certificates), to which Caddy's root is appended; its URL guard refuses
|
||||||
# private addresses with no switch, which the pasture's public-looking subnet passes. The admin is wpuser; the town's
|
# private addresses with no switch, which the pasture's public-looking subnet passes. The admin is wpuser; the town's
|
||||||
# accounts are authors with application passwords for the REST API.
|
# accounts are authors with application passwords for the REST API. Its automatic updates are off: one (core 7.1.2,
|
||||||
WORDPRESS_IMAGE=${WORDPRESS_IMAGE:-docker.io/library/wordpress:6-apache}
|
# 2026-10-05) wrote a new CA bundle over the one Caddy's root was appended to, and nothing reached PrivaPub after it.
|
||||||
|
WORDPRESS_IMAGE=${WORDPRESS_IMAGE:-docker.io/library/wordpress:7.1.2-apache}
|
||||||
WORDPRESS_CLI_IMAGE=${WORDPRESS_CLI_IMAGE:-docker.io/library/wordpress:cli}
|
WORDPRESS_CLI_IMAGE=${WORDPRESS_CLI_IMAGE:-docker.io/library/wordpress:cli}
|
||||||
WORDPRESS_ACTIVITYPUB=9.3.1
|
WORDPRESS_ACTIVITYPUB=9.3.1
|
||||||
WORDPRESS_PASSWORD=Wordpress-Pasture-1
|
WORDPRESS_PASSWORD=Wordpress-Pasture-1
|
||||||
@@ -24,7 +25,7 @@ wordpress_up() {
|
|||||||
# behind Caddy: https as the proxy says, and the site's own address
|
# behind Caddy: https as the proxy says, and the site's own address
|
||||||
local extra="if (isset(\$_SERVER['HTTP_X_FORWARDED_PROTO']) && \$_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { \$_SERVER['HTTPS'] = 'on'; }
|
local extra="if (isset(\$_SERVER['HTTP_X_FORWARDED_PROTO']) && \$_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { \$_SERVER['HTTPS'] = 'on'; }
|
||||||
define('WP_HOME', 'https://wordpress.test'); define('WP_SITEURL', 'https://wordpress.test'); define('DISABLE_WP_CRON', true);
|
define('WP_HOME', 'https://wordpress.test'); define('WP_SITEURL', 'https://wordpress.test'); define('DISABLE_WP_CRON', true);
|
||||||
define('FS_METHOD', 'direct');"
|
define('FS_METHOD', 'direct'); define('AUTOMATIC_UPDATER_DISABLED', true); define('WP_AUTO_UPDATE_CORE', false);"
|
||||||
podman run -d --replace --name pasture-wordpress --network $net \
|
podman run -d --replace --name pasture-wordpress --network $net \
|
||||||
-e WORDPRESS_DB_HOST=mysql -e WORDPRESS_DB_USER=pasture -e WORDPRESS_DB_PASSWORD=pasture -e WORDPRESS_DB_NAME=wordpress \
|
-e WORDPRESS_DB_HOST=mysql -e WORDPRESS_DB_USER=pasture -e WORDPRESS_DB_PASSWORD=pasture -e WORDPRESS_DB_NAME=wordpress \
|
||||||
-e WORDPRESS_CONFIG_EXTRA="$extra" -v pasture-wordpress-html:/var/www/html -v "$ca:/pasture/ca:z,ro" \
|
-e WORDPRESS_CONFIG_EXTRA="$extra" -v pasture-wordpress-html:/var/www/html -v "$ca:/pasture/ca:z,ro" \
|
||||||
|
|||||||
@@ -23,7 +23,9 @@ root=$(curl -s -X POST -H "Authorization: Bearer $AT" "$P/api/v1/statuses" -d "s
|
|||||||
root_uri=$(echo "$root" | j "print(d['uri'])")
|
root_uri=$(echo "$root" | j "print(d['uri'])")
|
||||||
reply_uri=$(curl -s -X POST -H "Authorization: Bearer $CT" "$P/api/v1/statuses" -d "status=an answer from carol $run&visibility=public&in_reply_to_id=$(echo "$root" | j "print(d['id'])")" | j "print(d['uri'])")
|
reply_uri=$(curl -s -X POST -H "Authorization: Bearer $CT" "$P/api/v1/statuses" -d "status=an answer from carol $run&visibility=public&in_reply_to_id=$(echo "$root" | j "print(d['id'])")" | j "print(d['uri'])")
|
||||||
until_true 45 '[ "$(m_rails "puts Status.exists?(uri: \"$root_uri\")")" = "true" ]' && ok "alice's post reaches Mastodon" || ko "alice's post never reached Mastodon"
|
until_true 45 '[ "$(m_rails "puts Status.exists?(uri: \"$root_uri\")")" = "true" ]' && ok "alice's post reaches Mastodon" || ko "alice's post never reached Mastodon"
|
||||||
[ "$(m_rails "puts Status.exists?(uri: \"$reply_uri\")")" = "false" ] && ok "carol's reply is not delivered there" || ko "carol's reply reached Mastodon unasked"
|
# (PrivaPub never sends it there; a relay Mastodon has just left, in the scenario before, may still pass it on)
|
||||||
|
p_sent_to_mastodon() { podman exec pasture-mongo mongosh --quiet PrivaPub --eval "print(db.Job.find({Kind: 0, CreatedAt: {\$gt: new Date(Date.now() - 600000)}}).toArray().filter(j => j.Payload.includes('\"Inbox\":\"https://mastodon.test') && j.Payload.includes('$1')).length)"; }
|
||||||
|
[ "$(p_sent_to_mastodon "$reply_uri")" = "0" ] && ok "carol's reply is not delivered there" || ko "PrivaPub delivered carol's reply to Mastodon unasked"
|
||||||
|
|
||||||
m_rails "Status.find_by(uri: \"$root_uri\").update_columns(created_at: 10.minutes.ago, fetched_replies_at: nil)" >/dev/null
|
m_rails "Status.find_by(uri: \"$root_uri\").update_columns(created_at: 10.minutes.ago, fetched_replies_at: nil)" >/dev/null
|
||||||
root_on_m=$(m_rails "puts Status.find_by(uri: \"$root_uri\").id")
|
root_on_m=$(m_rails "puts Status.find_by(uri: \"$root_uri\").id")
|
||||||
|
|||||||
Reference in new issue
Block a user