Owner decisions of 2026-10-06; personas' public posts go to relays
The owner decided four gated questions, now in ROADMAP: personas publish a wall (G-0009), their public posts go to the relays PrivaPub subscribes to, public threads publish their replies and context, and FEP-8fcf follower digests are sent. The first is in: a persona's own public post outside any group, its edit and its deletion also go to the relays that accepted us, as Mastodon sends them; nothing less public, and no boost. Checked live (scenarios/relay.sh, 15 checks): the post reaches Activity-Relay, and Mastodon through aode-relay's announce. Mastodon drops what Activity-Relay forwards without an LD signature or FEP-8b32 proof, which PrivaPub does not add yet. 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
b45321f28d
commit
93e13e5563
8 files changed
+70
-21
No files matched your search
@@ -591,7 +591,8 @@ tools/pasture/run.sh down # removes e
|
|||||||
`peers/aoderelay.sh` aode-relay 0.3.129 as `aoderelay.test`):** `appsettings.Pasture.json` names both in
|
`peers/aoderelay.sh` aode-relay 0.3.129 as `aoderelay.test`):** `appsettings.Pasture.json` names both in
|
||||||
`Federation:Relays`, so PrivaPub subscribes a minute after it starts. `scenarios/relay.sh` has Mastodon subscribe to
|
`Federation:Relays`, so PrivaPub subscribes a minute after it starts. `scenarios/relay.sh` has Mastodon subscribe to
|
||||||
each in turn, checks that a post of an account nobody here follows reaches the federated timeline (forwarded by one,
|
each in turn, checks that a post of an account nobody here follows reaches the federated timeline (forwarded by one,
|
||||||
announced by the other), and has Mastodon leave again, so the town sees no relayed posts. 13 checks.
|
announced by the other), that alice's public post goes to the relays (and through aode-relay to Mastodon) and nothing
|
||||||
|
less public, and has Mastodon leave again, so the town sees no relayed posts. 15 checks.
|
||||||
- **Smithereen (1.0.3):** its image on the shared MySQL (database `smithereen`, its schema from the image's commit),
|
- **Smithereen (1.0.3):** its image on the shared MySQL (database `smithereen`, its schema from the image's commit),
|
||||||
with imgproxy and a file server behind Caddy as `smithereen.test` (`/i` and `/s`), trusting the CA through a JDK
|
with imgproxy and a file server behind Caddy as `smithereen.test` (`/i` and `/s`), trusting the CA through a JDK
|
||||||
store with it added (`JAVA_TOOL_OPTIONS`). MySQL takes its stored functions only with
|
store with it added (`JAVA_TOOL_OPTIONS`). MySQL takes its stored functions only with
|
||||||
|
|||||||
+5
-2
@@ -265,8 +265,11 @@ Its instance actor follows `Public` at each, as Mastodon subscribes (`Federation
|
|||||||
and every six hours: an unanswered or refused subscription is asked again a day later, and a relay no longer named gets
|
and every six hours: an unanswered or refused subscription is asked again a day later, and a relay no longer named gets
|
||||||
the `Undo`). What an accepted relay passes on comes to the federated timeline, never to anyone's home: a public post it
|
the `Undo`). What an accepted relay passes on comes to the federated timeline, never to anyone's home: a public post it
|
||||||
forwards as its author sent it (Activity-Relay), read again from its origin like any forwarded post, and a post it
|
forwards as its author sent it (Activity-Relay), read again from its origin like any forwarded post, and a post it
|
||||||
announces (aode-relay), kept as its author's and never as the relay's boost. Nothing else is taken from a relay, and
|
announces (aode-relay), kept as its author's and never as the relay's boost. Nothing else is taken from a relay. A
|
||||||
nothing of a persona's is sent to one: sending public posts to relays waits for the owner.
|
persona's public post outside any group, its edit and its deletion also go to the relays that accepted us (owner decision
|
||||||
|
2026-10-06), as Mastodon sends them; nothing less public, and no boost. Mastodon takes a post Activity-Relay forwards
|
||||||
|
only with an LD signature or an FEP-8b32 proof, which PrivaPub does not yet add, so it reaches Mastodon through relays
|
||||||
|
that announce (aode-relay).
|
||||||
|
|
||||||
## Server descriptions and the crawler
|
## Server descriptions and the crawler
|
||||||
|
|
||||||
|
|||||||
@@ -104,6 +104,24 @@ namespace PrivaPub.Tests.Federation
|
|||||||
Assert.Equal(PostVisibility.Public, kept[0].Visibility);
|
Assert.Equal(PostVisibility.Public, kept[0].Visibility);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// owner decision 2026-10-06: a persona's public post, its edit and its deletion go to the relays too; nothing less
|
||||||
|
// public does, nor a boost
|
||||||
|
[Fact]
|
||||||
|
public async Task A_personas_public_post_goes_to_the_relays_and_nothing_less_public()
|
||||||
|
{
|
||||||
|
var relay = await Subscribed();
|
||||||
|
var (_, alice) = await _harness.Persona("alice");
|
||||||
|
var token = Token;
|
||||||
|
|
||||||
|
var open = await _harness.Statuses.Publish(alice, new PrivaPub.Domain.Statuses.StatusDraft { Text = "for everyone", Visibility = PostVisibility.Public }, token);
|
||||||
|
await _harness.Statuses.Publish(alice, new PrivaPub.Domain.Statuses.StatusDraft { Text = "quietly", Visibility = PostVisibility.Unlisted }, token);
|
||||||
|
await _harness.Statuses.Publish(alice, new PrivaPub.Domain.Statuses.StatusDraft { Text = "for followers", Visibility = PostVisibility.FollowersOnly }, token);
|
||||||
|
|
||||||
|
var sent = (await _harness.Outgoing(relay.Id + "/inbox")).Where(a => a["type"]!.GetValue<string>() == "Create").ToList();
|
||||||
|
var create = Assert.Single(sent);
|
||||||
|
Assert.Equal(alice.PostUri(open.Post.ID), create["object"]!["id"]!.GetValue<string>());
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task A_post_a_relay_announces_is_its_authors_never_the_relays_boost()
|
public async Task A_post_a_relay_announces_is_its_authors_never_the_relays_boost()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -44,13 +44,14 @@ namespace PrivaPub.Tests.Support
|
|||||||
Local = new LocalActorService(Db, new StaticOptions<AppConfiguration>(new AppConfiguration { BackendBaseAddress = Base }));
|
Local = new LocalActorService(Db, new StaticOptions<AppConfiguration>(new AppConfiguration { BackendBaseAddress = Base }));
|
||||||
Remote = new RemoteActorService(Peer.Http(cache), Local, cache, Db);
|
Remote = new RemoteActorService(Peer.Http(cache), Local, cache, Db);
|
||||||
Delivery = new DeliveryService(Db, Queue);
|
Delivery = new DeliveryService(Db, Queue);
|
||||||
|
Relays = new Relays(Microsoft.Extensions.Options.Options.Create(RelayOptions), Remote, Local, Delivery);
|
||||||
Fanout = new Fanout(Db);
|
Fanout = new Fanout(Db);
|
||||||
Groups = new GroupDistributor(Delivery);
|
Groups = new GroupDistributor(Delivery);
|
||||||
Records = new ObjectRecords(Queue);
|
Records = new ObjectRecords(Queue);
|
||||||
Polls = new PollService(Db, Local, Delivery, Queue);
|
Polls = new PollService(Db, Local, Delivery, Queue);
|
||||||
Reactions = new Reactions(Db, Delivery);
|
Reactions = new Reactions(Db, Delivery);
|
||||||
RemotePosts = new RemotePosts(Db, Local, Remote, new NoBlocks(), Queue, Records, new NoPreviews());
|
RemotePosts = new RemotePosts(Db, Local, Remote, new NoBlocks(), Queue, Records, new NoPreviews());
|
||||||
Outbox = new OutboxPublisher(Db, Local, Delivery);
|
Outbox = new OutboxPublisher(Db, Local, Delivery, Relays);
|
||||||
Quotes = new QuoteService(Db, Remote, RemotePosts, Local, Delivery, Outbox);
|
Quotes = new QuoteService(Db, Remote, RemotePosts, Local, Delivery, Outbox);
|
||||||
Approvals = new InteractionApprovals(Db, Remote, Local, Delivery, Outbox);
|
Approvals = new InteractionApprovals(Db, Remote, Local, Delivery, Outbox);
|
||||||
Participations = new Participations(Db, Local, Delivery);
|
Participations = new Participations(Db, Local, Delivery);
|
||||||
@@ -58,7 +59,6 @@ namespace PrivaPub.Tests.Support
|
|||||||
Follows = new FollowService(Db, Local, Remote, Delivery, new KeyLocalizer<GenericRes>(), NullLogger<FollowService>.Instance);
|
Follows = new FollowService(Db, Local, Remote, Delivery, new KeyLocalizer<GenericRes>(), NullLogger<FollowService>.Instance);
|
||||||
Relationships = new RelationshipService(Db, Follows, Delivery);
|
Relationships = new RelationshipService(Db, Follows, Delivery);
|
||||||
Featured = new FeaturedPosts(Db, Remote, RemotePosts);
|
Featured = new FeaturedPosts(Db, Remote, RemotePosts);
|
||||||
Relays = new Relays(Microsoft.Extensions.Options.Options.Create(RelayOptions), Remote, Local, Delivery);
|
|
||||||
Handlers = new IActivityHandler[]
|
Handlers = new IActivityHandler[]
|
||||||
{
|
{
|
||||||
new FollowHandler(Db, Local, Remote, Delivery),
|
new FollowHandler(Db, Local, Remote, Delivery),
|
||||||
|
|||||||
@@ -28,9 +28,11 @@ namespace PrivaPub.Federation.Outbox
|
|||||||
readonly DbEntities _dbEntities;
|
readonly DbEntities _dbEntities;
|
||||||
readonly ILocalActorService _localActors;
|
readonly ILocalActorService _localActors;
|
||||||
readonly IDeliveryService _delivery;
|
readonly IDeliveryService _delivery;
|
||||||
|
readonly Relays.IRelays _relays;
|
||||||
|
|
||||||
public OutboxPublisher(DbEntities dbEntities, ILocalActorService localActors, IDeliveryService delivery)
|
public OutboxPublisher(DbEntities dbEntities, ILocalActorService localActors, IDeliveryService delivery, Relays.IRelays relays = default)
|
||||||
{
|
{
|
||||||
|
_relays = relays;
|
||||||
_dbEntities = dbEntities;
|
_dbEntities = dbEntities;
|
||||||
_localActors = localActors;
|
_localActors = localActors;
|
||||||
_delivery = delivery;
|
_delivery = delivery;
|
||||||
@@ -79,6 +81,12 @@ namespace PrivaPub.Federation.Outbox
|
|||||||
inboxes.Add(inbox);
|
inboxes.Add(inbox);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// a persona's own public post, outside any group, also goes to the relays we subscribe to (owner decision
|
||||||
|
// 2026-10-06), its edits and deletion with it
|
||||||
|
if (_relays != default && post.Visibility == PostVisibility.Public && author.Kind == LocalActorKind.Person
|
||||||
|
&& string.IsNullOrEmpty(post.ReblogOfPostId) && string.IsNullOrEmpty(post.GroupId))
|
||||||
|
inboxes.AddRange(await _relays.Inboxes(token));
|
||||||
|
|
||||||
return inboxes.Where(i => !string.IsNullOrEmpty(i)).Distinct(StringComparer.Ordinal).ToList();
|
return inboxes.Where(i => !string.IsNullOrEmpty(i)).Distinct(StringComparer.Ordinal).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,11 +21,13 @@ namespace PrivaPub.Federation.Relays
|
|||||||
Task Reconcile(CancellationToken token);
|
Task Reconcile(CancellationToken token);
|
||||||
Task<bool> Answered(JsonNode activity, ForeignAvatar actor, bool accepted, CancellationToken token);
|
Task<bool> Answered(JsonNode activity, ForeignAvatar actor, bool accepted, CancellationToken token);
|
||||||
Task<bool> Passes(string actorUri, CancellationToken token);
|
Task<bool> Passes(string actorUri, CancellationToken token);
|
||||||
|
Task<IReadOnlyList<string>> Inboxes(CancellationToken token);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Relays (Activity-Relay, aode-relay, pub-relay): the instance actor follows Public at each relay the configuration
|
// Relays (Activity-Relay, aode-relay, pub-relay): the instance actor follows Public at each relay the configuration
|
||||||
// names, as Mastodon subscribes, and takes what they pass on: public posts, forwarded as their authors sent them (read
|
// names, as Mastodon subscribes, and takes what they pass on: public posts, forwarded as their authors sent them (read
|
||||||
// again from their origin, as any forwarded post) or announced by the relay. Nothing of a persona's is sent to a relay.
|
// again from their origin, as any forwarded post) or announced by the relay. A persona's public posts go to the relays
|
||||||
|
// that accepted us (owner decision 2026-10-06), as Mastodon sends them; nothing else of a persona's does.
|
||||||
public class Relays : IRelays
|
public class Relays : IRelays
|
||||||
{
|
{
|
||||||
static readonly TimeSpan AskAgain = TimeSpan.FromDays(1);
|
static readonly TimeSpan AskAgain = TimeSpan.FromDays(1);
|
||||||
@@ -108,6 +110,11 @@ namespace PrivaPub.Federation.Relays
|
|||||||
return accepted.Contains(actorUri);
|
return accepted.Contains(actorUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the inboxes of the relays that accepted our subscription, where a persona's public posts also go
|
||||||
|
public async Task<IReadOnlyList<string>> Inboxes(CancellationToken token) =>
|
||||||
|
(await DB.Default.Find<RelaySubscription>().Match(s => s.State == RelayState.Accepted).ExecuteAsync(token))
|
||||||
|
.Select(s => s.InboxURL).Where(i => !string.IsNullOrEmpty(i)).Distinct(StringComparer.Ordinal).ToList();
|
||||||
|
|
||||||
// the relay's actor, from its address or, for a relay named by its inbox, from the /actor beside it
|
// the relay's actor, from its address or, for a relay named by its inbox, from the /actor beside it
|
||||||
async Task<ForeignAvatar> Resolve(string address, CancellationToken token)
|
async Task<ForeignAvatar> Resolve(string address, CancellationToken token)
|
||||||
{
|
{
|
||||||
|
|||||||
+12
-6
@@ -278,9 +278,14 @@ and circles (see Owner decisions).
|
|||||||
| An account a persona follows moves | **Move the follow, as Mastodon does.** After a verified `Move` the persona follows the new account (a Follow to its server) and unfollows the old, in the same lists; a mute or a block of the old account carries over. |
|
| An account a persona follows moves | **Move the follow, as Mastodon does.** After a verified `Move` the persona follows the new account (a Follow to its server) and unfollows the old, in the same lists; a mute or a block of the old account carries over. |
|
||||||
| Should PrivaPub pass on replies to a persona's posts? | **Yes, "the fediverse is broken without".** A public or unlisted reply that someone on another server writes to a persona's post goes on to the persona's followers, as Mastodon forwards it: the activity as its author signed it, never to the replier's own server, never for a post that is local-only, in a group or not shown to followers. Its edits and deletion follow the same way. |
|
| Should PrivaPub pass on replies to a persona's posts? | **Yes, "the fediverse is broken without".** A public or unlisted reply that someone on another server writes to a persona's post goes on to the persona's followers, as Mastodon forwards it: the activity as its author signed it, never to the replier's own server, never for a post that is local-only, in a group or not shown to followers. Its edits and deletion follow the same way. |
|
||||||
|
|
||||||
**Waiting for the owner:** a persona's wall (G-0009). Smithereen sends a post written on someone else's wall only to
|
### Owner decisions on walls, relays, threads and followers (2026-10-06)
|
||||||
servers whose actors publish a wall (`sm:wall`, FEP-400e). Publishing one would also let Smithereen's users write on a
|
|
||||||
persona's wall, and PrivaPub would then host their posts and announce them with `Add{Note}`.
|
| Question | Decision |
|
||||||
|
|---|---|
|
||||||
|
| A persona's wall (G-0009) | **Yes, publish walls.** A persona's actor names its wall (`sm:wall`, FEP-400e); Smithereen's users may write on it, PrivaPub hosts their posts there and tells the persona's followers with `Add{Note}`. |
|
||||||
|
| Personas' public posts and relays | **Send public posts too.** A persona's public post (not unlisted, not followers-only, not local-only) also goes to the relays PrivaPub subscribes to, as Mastodon sends them. |
|
||||||
|
| A post's `replies` and `context` | **Publish public threads.** Public and unlisted posts name their `replies` and `context` collections, which list only the public and unlisted replies PrivaPub holds; followers-only, circle, direct and local-only posts never do. |
|
||||||
|
| FEP-8fcf followers synchronisation | **Send digests.** A delivery to a server that the persona's followers there would get carries a `Collection-Synchronization` header: a digest of the persona's followers on that server only, and where that server reads that partial list. |
|
||||||
|
|
||||||
## Libraries (researched; no maintained .NET ActivityPub library exists, so Letterbook and Iceshrimp.NET both wrote their own)
|
## Libraries (researched; no maintained .NET ActivityPub library exists, so Letterbook and Iceshrimp.NET both wrote their own)
|
||||||
|
|
||||||
@@ -682,9 +687,10 @@ it, raw where it doesn't.
|
|||||||
- FEP-8b32 proof verification;
|
- FEP-8b32 proof verification;
|
||||||
- `hs2019` with SHA-512.
|
- `hs2019` with SHA-512.
|
||||||
- **Discovery:**
|
- **Discovery:**
|
||||||
- a relay client for both relay styles: **reading done 2026-10-05** (`Federation:Relays`; forwarded posts read again
|
- a relay client for both relay styles: **done 2026-10-05/06** (`Federation:Relays`; forwarded posts read again
|
||||||
from their origin, announces unwrapped; checked live against Activity-Relay and aode-relay); sending public posts to
|
from their origin, announces unwrapped; personas' public posts sent to them, owner decision; checked live against
|
||||||
relays waits for the owner;
|
Activity-Relay and aode-relay). Mastodon drops what Activity-Relay forwards without an LD signature or FEP-8b32
|
||||||
|
proof;
|
||||||
- instance actor discovery (FEP-d556, FEP-2677);
|
- instance actor discovery (FEP-d556, FEP-2677);
|
||||||
- `implements` (FEP-844e).
|
- `implements` (FEP-844e).
|
||||||
- **Mastodon API:** ~~streaming WebSocket~~ (done 2026-10-05: `/api/v1/streaming` as a WebSocket and as server-sent
|
- **Mastodon API:** ~~streaming WebSocket~~ (done 2026-10-05: `/api/v1/streaming` as a WebSocket and as server-sent
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
# Relays as PrivaPub reads them (Federation:Relays in appsettings.Pasture.json): Activity-Relay, which forwards what its
|
# Relays as PrivaPub uses them (Federation:Relays in appsettings.Pasture.json): Activity-Relay, which forwards what its
|
||||||
# subscribers send, and aode-relay, which announces it. For each, the instance actor subscribes, Mastodon subscribes too,
|
# subscribers send, and aode-relay, which announces it. For each, the instance actor subscribes, Mastodon subscribes too,
|
||||||
# and a public post of a Mastodon account nobody here follows reaches PrivaPub's federated timeline through the relay;
|
# a public post of a Mastodon account nobody here follows reaches PrivaPub's federated timeline through the relay, and a
|
||||||
# nothing of a persona's goes to a relay. Mastodon leaves each relay after, so the town sees no relayed posts. Needs the
|
# persona's public post goes to the relay (owner decision 2026-10-06), nothing less public. Mastodon leaves each relay
|
||||||
# relay, aoderelay and mastodon peers.
|
# after, so the town sees no relayed posts. Needs the relay, aoderelay and mastodon peers.
|
||||||
M=https://mastodon.test:6443
|
M=https://mastodon.test:6443
|
||||||
mcurl() { curl -sk --resolve mastodon.test:6443:127.0.0.1 "$@"; }
|
mcurl() { curl -sk --resolve mastodon.test:6443:127.0.0.1 "$@"; }
|
||||||
. "$here/peers/mastodon.sh"
|
. "$here/peers/mastodon.sh"
|
||||||
@@ -36,10 +36,12 @@ s_uri=$(relayed_post relay)
|
|||||||
until_true 60 'p_public_has "$s_uri"' && ok "a public post of an account nobody here follows reaches the federated timeline, forwarded" || ko "the forwarded post never arrived"
|
until_true 60 'p_public_has "$s_uri"' && ok "a public post of an account nobody here follows reaches the federated timeline, forwarded" || ko "the forwarded post never arrived"
|
||||||
[ "$(curl -s -H "$PH" "$P/api/v1/timelines/home?limit=40" | j "print(any(s['uri'] == '$s_uri' for s in d))")" = "False" ] \
|
[ "$(curl -s -H "$PH" "$P/api/v1/timelines/home?limit=40" | j "print(any(s['uri'] == '$s_uri' for s in d))")" = "False" ] \
|
||||||
&& ok "and no one's home" || ko "the relayed post landed in alice's home"
|
&& ok "and no one's home" || ko "the relayed post landed in alice's home"
|
||||||
p_post=$(curl -s -X POST -H "$PH" "$P/api/v1/statuses" -d "status=a PrivaPub post the relay never sees $run&visibility=public" | j "print(d['uri'])")
|
# relay_creates <text>: the Creates PrivaPub has queued for relay.test naming the text
|
||||||
sleep 5
|
relay_creates() { podman exec pasture-mongo mongosh --quiet PrivaPub --eval 'print(db.Job.countDocuments({Host:"relay.test", Payload:/Create/, Payload:/'"$1"'/}))'; }
|
||||||
[ "$(podman exec pasture-mongo mongosh --quiet PrivaPub --eval 'print(db.Job.countDocuments({Host:"relay.test", Payload:/Create/}))')" = "0" ] \
|
curl -s -o /dev/null -X POST -H "$PH" "$P/api/v1/statuses" -d "status=a PrivaPub post for the relay $run&visibility=public"
|
||||||
&& ok "nothing of a persona's goes to the relay" || ko "PrivaPub sent the relay a post"
|
curl -s -o /dev/null -X POST -H "$PH" "$P/api/v1/statuses" -d "status=a quiet PrivaPub post $run&visibility=unlisted"
|
||||||
|
until_true 30 '[ "$(relay_creates "a PrivaPub post for the relay $run")" = "1" ]' && ok "alice's public post goes to the relay" || ko "PrivaPub never sent the relay alice's public post"
|
||||||
|
[ "$(relay_creates "a quiet PrivaPub post $run")" = "0" ] && ok "and nothing less public" || ko "PrivaPub sent the relay an unlisted post"
|
||||||
|
|
||||||
m_unrelay relay.test
|
m_unrelay relay.test
|
||||||
until_true 45 '! relay_subscribers | grep -qx mastodon.test' && ok "Mastodon leaves Activity-Relay" || ko "Mastodon is still subscribed to Activity-Relay"
|
until_true 45 '! relay_subscribers | grep -qx mastodon.test' && ok "Mastodon leaves Activity-Relay" || ko "Mastodon is still subscribed to Activity-Relay"
|
||||||
@@ -52,5 +54,9 @@ a_uri=$(relayed_post aoderelay)
|
|||||||
until_true 60 'p_public_has "$a_uri"' && ok "a post aode-relay announces reaches the federated timeline as its author's" || ko "the announced post never arrived"
|
until_true 60 'p_public_has "$a_uri"' && ok "a post aode-relay announces reaches the federated timeline as its author's" || ko "the announced post never arrived"
|
||||||
[ "$(curl -s -H "$PH" "$P/api/v1/timelines/public?remote=true&limit=40" | j "print(any((s.get('reblog') or {}).get('uri') == '$a_uri' for s in d))")" = "False" ] \
|
[ "$(curl -s -H "$PH" "$P/api/v1/timelines/public?remote=true&limit=40" | j "print(any((s.get('reblog') or {}).get('uri') == '$a_uri' for s in d))")" = "False" ] \
|
||||||
&& ok "never as the relay's boost" || ko "the relay's announce shows as a boost"
|
&& ok "never as the relay's boost" || ko "the relay's announce shows as a boost"
|
||||||
|
# alice's public post reaches Mastodon through aode-relay's announce, though nobody there follows her
|
||||||
|
a_post=$(curl -s -X POST -H "$PH" "$P/api/v1/statuses" -d "status=a PrivaPub post aode-relay brings $run&visibility=public" | j "print(d['uri'])")
|
||||||
|
until_true 60 '[ "$(podman exec pasture-mastodon bin/rails runner "puts Status.exists?(uri: \"$a_post\")" 2>/dev/null | tail -1)" = "true" ]' \
|
||||||
|
&& ok "alice's public post reaches Mastodon through aode-relay" || ko "alice's post never reached Mastodon through aode-relay"
|
||||||
m_unrelay aoderelay.test
|
m_unrelay aoderelay.test
|
||||||
until_true 45 '! aoderelay_connected | grep -q mastodon.test' && ok "Mastodon leaves aode-relay" || ko "Mastodon is still subscribed to aode-relay"
|
until_true 45 '! aoderelay_connected | grep -q mastodon.test' && ok "Mastodon leaves aode-relay" || ko "Mastodon is still subscribed to aode-relay"
|
||||||
Reference in new issue
Block a user