test(federation-identity): #3 soft / #5 full — DB cascade verification + setup fixture

Adds setupFullDeletionFixture (federated user joins remote space, authors 2
messages with reactions, opens 1-on-1 DM with a live observer). Tests #3 (soft
mode: tombstone + dm_members cleared, messages/reactions retained) and #5 (full
mode: tombstone + messages/reactions purged, surviving 1-on-1 DM channel).

Also fixes seedPeer to install both the URL form (outbound lookup on sender)
and the DOMAIN-claim form (inbound auth on receiver) — required because the
test harness's ephemeral http://127.0.0.1 origin and DOMAIN-derived
getOurOrigin() return different strings, while production has them coincide.
This was latent: test #1 (leave mode) skips S2S, so #3 was the first test to
actually exercise the S2S delete path and surfaced the dual-origin gap.
This commit is contained in:
Jannis Braun
2026-05-03 23:46:20 +02:00
parent 957cfd9094
commit c5e3d36689
2 changed files with 207 additions and 0 deletions
+23
View File
@@ -5,6 +5,21 @@ import type { SpawnedInstance } from './twoInstanceHarness.js';
* Install matching federation_peers rows on both instances pointing at each other,
* with a single shared HMAC secret. Returns the secret for tests that need to sign
* raw S2S requests directly.
*
* IMPORTANT — dual-origin reality in tests:
* Production code stores `peer.origin` as a single string and uses it for BOTH
* (a) outbound URL: `fetch(${peer.origin}/api/...)`, AND
* (b) inbound auth: `WHERE origin = X-Federation-Origin` claim from inbound headers.
* In production with `DOMAIN=example.com`, both reduce to `https://example.com`.
*
* In our test harness, the URL is `http://127.0.0.1:<ephemeral>` but `getOurOrigin()`
* returns `https://${DOMAIN}` (= `https://home.test.local`). These two values are
* DIFFERENT, so we cannot satisfy both with one `peer.origin` row.
*
* Workaround: insert TWO rows per direction — one with the URL form (for outbound
* lookup on the sender) and one with the DOMAIN-claim form (for inbound auth on
* the receiver). The schema has a UNIQUE constraint on `origin`, but the two
* rows have distinct origins so there is no conflict.
*/
export async function peerInstances(
a: SpawnedInstance,
@@ -29,9 +44,17 @@ export async function peerInstances(
}
};
// Outbound lookup form (URL) — what users.ts / federation.ts use to find the
// hmacSecret given a body-supplied or DB-stored origin URL.
await seedOn(a, b.origin, b.domain);
await seedOn(b, a.origin, a.domain);
// Inbound auth form (DOMAIN claim) — what the receiver uses to look up the
// peer when validating the X-Federation-Origin header from a sender whose
// `getOurOrigin()` returns `https://${DOMAIN}`.
await seedOn(a, `https://${b.domain}`, b.domain);
await seedOn(b, `https://${a.domain}`, a.domain);
return sharedSecret;
}