Files
thepraandClaude Opus 5.5 01e5aa4ddd Pasture: Pixelfed and WordPress join
Pixelfed 0.14.4 (FrankenPHP with Horizon and the scheduler, on the shared
Postgres and Redis) and WordPress 6 with ActivityPub 9.3.1 (on a new shared
MySQL, WP-Cron run by a sidecar) are peers now, each with its scenario:
Pixelfed 26 checks (photos both ways with alt text, its place arriving as
Rome with its coordinates, comments, likes, a boost, edits and deletes),
WordPress 17 (an Article with its title, our reply, like and boost kept as
comments of their kinds, its edit and removal). Pixelfed has a town driver
and a pair spec: 145 checks pass, 2 expected (G-0007).

What they showed: Pixelfed names our posts by their page (fixed in
26dac40); on PostgreSQL its migration making caption nullable never runs,
so every remote boost failed (the pasture applies it); it files a DM it
fetches as followers-only (G-0007, upstream); Passport refuses a token
whose user id equals its client's id. WordPress signs with RFC 9421
first, which PrivaPub now verifies (c5a69d2).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
2026-10-05 07:01:38 +02:00

93 lines
7.8 KiB
Bash

# Pixelfed 0.14: follows both ways; photo posts both ways with their alt text, Pixelfed's with its place (a city of its
# own list), shown on PrivaPub with that place; comments both ways; likes and a boost; an edit and deletes both ways;
# statistics. What Pixelfed holds is read from its Postgres (database pixelfed), never fetched.
PF=https://pixelfed.test:6443
pfc() { curl -sk --resolve pixelfed.test:6443:127.0.0.1 "$@"; }
FT=$(cat "$here/.state/pixelfed.token" 2>/dev/null)
FH="Authorization: Bearer $FT"
# pf_sql <sql>: one value from Pixelfed's database
pf_sql() { podman exec pasture-postgres psql -U pasture -d pixelfed -Atc "$1"; }
# pf_photo <text> <alt> [place_id]: a photo post by pfuser, its id
pf_photo() {
local media
make_png "$work/pf.png"
media=$(pfc -H "$FH" -X POST "$PF/api/v1/media" -F "file=@$work/pf.png;type=image/png" -F "description=$2" | j "print(d['id'])")
pfc -H "$FH" -X POST "$PF/api/v1/statuses" --data-urlencode "status=$1" -d visibility=public -d "media_ids[]=$media" \
${3:+-d place_id=$3} | j "print(d['id'])"
}
# a PrivaPub status in alice_pixelfed's home whose text has the given words
p_home_id() { curl -s -H "$PH" "$P/api/v1/timelines/home?limit=40" | j "print(next((o['id'] for o in ((s.get('reblog') or s) for s in d) if '$1' in (o['content'] or '')), ''))"; }
echo "pixelfed"
[ -n "$FT" ] && ok "Pixelfed token for pfuser" || { ko "Pixelfed token"; return 1; }
PT=$(privapub_token alice_pixelfed)
PH="Authorization: Bearer $PT"
[ -n "$PT" ] && ok "PrivaPub token for alice_pixelfed" || { ko "PrivaPub token for alice_pixelfed"; return 1; }
echo " discovery and follows"
alice_on_pf=$(pfc -H "$FH" "$PF/api/v2/search?q=@alice_pixelfed@privapub.test&resolve=true&type=accounts" | j "print(d['accounts'][0]['id'])")
[ -n "$alice_on_pf" ] && ok "Pixelfed resolves @alice_pixelfed@privapub.test" || ko "Pixelfed cannot resolve alice_pixelfed"
pf_on_p=$(curl -s -H "$PH" "$P/api/v2/search?q=pfuser@pixelfed.test&resolve=true&type=accounts" | j "print(d['accounts'][0]['id'])")
[ -n "$pf_on_p" ] && ok "PrivaPub resolves @pfuser@pixelfed.test" || ko "PrivaPub cannot resolve pfuser"
pfc -o /dev/null -H "$FH" -X POST "$PF/api/v1/accounts/$alice_on_pf/follow"
until_true 30 '[ "$(pfc -H "$FH" "$PF/api/v1/accounts/relationships?id[]=$alice_on_pf" | j "print(d[0][\"following\"])")" = "True" ]' \
&& ok "pfuser follows alice_pixelfed (Accept arrived)" || ko "Pixelfed's follow not accepted"
curl -s -o /dev/null -X POST -H "$PH" "$P/api/v1/accounts/$pf_on_p/follow"
until_true 30 '[ "$(curl -s -H "$PH" "$P/api/v1/accounts/relationships?id[]=$pf_on_p" | j "print(d[0][\"following\"])")" = "True" ]' \
&& ok "alice_pixelfed follows pfuser (Accept arrived)" || ko "PrivaPub's follow not accepted"
echo " photos"
rome=$(pf_sql "select id from places where name = 'Rome' and country = 'Italy' limit 1")
pf_post=$(pf_photo "A Pixelfed photo from Rome" "a red square in Rome" "$rome")
[ -n "$pf_post" ] && ok "pfuser posts a photo with a place" || ko "Pixelfed refused the photo"
until_true 45 '[ -n "$(p_home_id "A Pixelfed photo from Rome")" ]' && ok "pfuser's photo reaches alice_pixelfed's home" || ko "pfuser's photo never arrived"
pf_on_p_post=$(p_home_id "A Pixelfed photo from Rome")
pf_status=$(curl -s -H "$PH" "$P/api/v1/statuses/$pf_on_p_post")
[ "$(echo "$pf_status" | j "print(d['media_attachments'][0]['description'])")" = "a red square in Rome" ] && ok "its alt text arrives" || ko "its alt text is lost"
case "$(echo "$pf_status" | j "print(d['media_attachments'][0]['url'])")" in
*privapub.test/*) ok "its picture is served through PrivaPub's proxy" ;;
*) ko "its picture is not proxied" ;;
esac
[ "$(echo "$pf_status" | j "p=(d.get('privapub') or {}).get('place') or {}; print(p.get('name'), round(p.get('latitude') or 0), round(p.get('longitude') or 0))")" = "Rome 42 13" ] \
&& ok "its place arrives: Rome, at its coordinates" || ko "its place is lost: $(echo "$pf_status" | j "print((d.get('privapub') or {}).get('place'))")"
make_png "$work/photo.png"
p_media=$(curl -s -H "$PH" -X POST "$P/api/v2/media" -F "file=@$work/photo.png;type=image/png" -F "description=a red square from PrivaPub" | j "print(d['id'])")
p_post=$(curl -s -H "$PH" -X POST "$P/api/v1/statuses" -d "status=A PrivaPub photo for Pixelfed&visibility=public&media_ids[]=$p_media")
p_post_id=$(echo "$p_post" | j "print(d['id'])"); p_post_uri=$(echo "$p_post" | j "print(d['uri'])")
until_true 45 '[ -n "$(pf_sql "select id from statuses where uri = '"'$p_post_uri'"' or object_url = '"'$p_post_uri'"'")" ]' \
&& ok "alice_pixelfed's photo reaches Pixelfed" || ko "alice_pixelfed's photo missing on Pixelfed"
p_on_pf=$(pf_sql "select id from statuses where uri = '$p_post_uri' or object_url = '$p_post_uri'")
[ "$(pf_sql "select caption from media where status_id = '$p_on_pf'")" = "a red square from PrivaPub" ] && ok "its alt text arrives on Pixelfed" || ko "its alt text is lost on Pixelfed"
echo " comments"
pfc -o /dev/null -H "$FH" -X POST "$PF/api/v1/statuses" --data-urlencode "status=@alice_pixelfed@privapub.test a Pixelfed comment" -d "in_reply_to_id=$p_on_pf" -d visibility=public
until_true 45 '[ "$(curl -s -H "$PH" "$P/api/v1/statuses/$p_post_id/context" | j "print(any(\"a Pixelfed comment\" in s[\"content\"] for s in d[\"descendants\"]))")" = "True" ]' \
&& ok "pfuser's comment threads under alice_pixelfed's photo" || ko "pfuser's comment missing on PrivaPub"
curl -s -o /dev/null -X POST -H "$PH" "$P/api/v1/statuses" -d "status=@pfuser@pixelfed.test a PrivaPub comment&in_reply_to_id=$pf_on_p_post&visibility=public"
until_true 45 '[ "$(pf_sql "select count(*) from statuses where in_reply_to_id = '"'$pf_post'"' and caption like '"'%a PrivaPub comment%'"'")" = "1" ]' \
&& ok "alice_pixelfed's comment threads under pfuser's photo on Pixelfed" || ko "alice_pixelfed's comment missing on Pixelfed"
echo " likes and boosts"
curl -s -o /dev/null -X POST -H "$PH" "$P/api/v1/statuses/$pf_on_p_post/favourite"
until_true 45 '[ "$(pf_sql "select likes_count from statuses where id = '"'$pf_post'"'")" = "1" ]' && ok "alice_pixelfed's like counts on Pixelfed" || ko "like not counted on Pixelfed"
curl -s -o /dev/null -X POST -H "$PH" "$P/api/v1/statuses/$pf_on_p_post/reblog"
until_true 45 '[ "$(pf_sql "select reblogs_count from statuses where id = '"'$pf_post'"'")" = "1" ]' && ok "alice_pixelfed's boost counts on Pixelfed" || ko "boost not counted on Pixelfed"
pfc -o /dev/null -H "$FH" -X POST "$PF/api/v1/statuses/$p_on_pf/favourite"
until_true 45 '[ "$(curl -s -H "$PH" "$P/api/v1/statuses/$p_post_id" | j "print(d[\"favourites_count\"])")" = "1" ]' && ok "pfuser's like counts on PrivaPub" || ko "Pixelfed's like not counted"
curl -s -o /dev/null -X POST -H "$PH" "$P/api/v1/statuses/$pf_on_p_post/unfavourite"
until_true 45 '[ "$(pf_sql "select likes_count from statuses where id = '"'$pf_post'"'")" = "0" ]' && ok "alice_pixelfed's unlike reaches Pixelfed" || ko "unlike not applied on Pixelfed"
echo " edits and deletes"
pfc -o /dev/null -H "$FH" -X PUT "$PF/api/v1/statuses/$pf_post" --data-urlencode "status=A Pixelfed photo from Rome, edited"
until_true 45 '[ "$(curl -s -H "$PH" "$P/api/v1/statuses/$pf_on_p_post" | j "print(\"edited\" in d[\"content\"] and d[\"edited_at\"] is not None)")" = "True" ]' \
&& ok "pfuser's edit reaches PrivaPub" || ko "Pixelfed's edit not applied"
curl -s -o /dev/null -X DELETE -H "$PH" "$P/api/v1/statuses/$p_post_id"
until_true 45 '[ -z "$(pf_sql "select id from statuses where id = '"'$p_on_pf'"' and deleted_at is null")" ]' \
&& ok "alice_pixelfed's delete reaches Pixelfed" || ko "delete not applied on Pixelfed"
pfc -o /dev/null -H "$FH" -X DELETE "$PF/api/v1/statuses/$pf_post"
until_true 45 '[ "$(curl -s -o /dev/null -w "%{http_code}" -H "$PH" "$P/api/v1/statuses/$pf_on_p_post")" = "404" ]' \
&& ok "pfuser's delete reaches PrivaPub" || ko "Pixelfed's delete not applied"
echo " statistics"
stats_check pixelfed.test pixelfed