0020-fediverse-interop-tests.md 5994 octets

RFC 0020 — Fediverse: tests d'interopérabilité wiremock (signed delivery round-trip)

  • Auteur : EBO (rustwarden)
  • Date : 2026-05-10
  • Statut : Accepted (auto-revue mainteneur unique 2026-05-10, score 26/35)
  • Apps consommatrices concernées : toute app fediverse en production qui veut une garantie reproductible que les signatures HTTP draft-cavage produites localement sont vérifiables par un récepteur tiers (Mastodon-style).
  • Plan associé : Phase 5 — production polish.
  • Dépendances : RFC 0015 (signatures), RFC 0016 (HttpSignedDelivery), RFC 0017 (auto-resolve), RFC 0011 (file outbound).

Summary

Ajouter un binaire de tests d'intégration tests/fediverse_interop.rs dans rustwarden-core qui monte un serveur HTTP local via wiremock joué comme « faux Mastodon ». Trois scénarios :

  1. Sign + verify round-trip : la couche HttpSignedDelivery (couche privée) signe un POST application/activity+json, le serveur capture la requête, et le test re-vérifie la signature en local avec parse_and_verify_cavage.
  2. Inbox 202 → delivered : drain_one contre une route wiremock qui répond 202 Accepted met la row à Delivered.
  3. Inbox 503 → deferred : même chose mais avec 503 Service Unavailable ; la row reste Pending avec next_retry_at calé sur le ladder RFC 0010.

Aucune nouvelle API publique. Aucune nouvelle migration. Une seule nouvelle dev-dependency : wiremock = "0.6".

Motivation

Sans tests interop, les RFCs 0015–0017 reposent sur des unit tests qui exercent les fonctions pures (rsa_sha256_sign, parse_signature_header). Aucun chemin n'exerce le moteur HTTP réel ni la sérialisation Date/Host/Signature telle que reqwest la transmet. Un mismatch silencieux (capitalisation des noms d'header, espaces, ré-encodage URL) ne sera détecté qu'en production face à Mastodon.

Le master plan §10 Phase 5 : « tests interop avec Mastodon : profil discoverable mais auth refusée proprement (degrade gracieux selon interop_scope) ». Cette RFC livre le squelette générique réutilisable ; les scénarios spécifiques (NodeInfo refus, auth fédérée e2e) restent ouverts pour des RFCs successives qui ré-utiliseront le même harness.

Non-goals

  • Pas de Docker Mastodon réel : trop coûteux en CI (image Ruby + DB Postgres dédiée). Le master plan §11 prévoit docker-compose.fediverse-test.yml pour les tests #[ignore] manuels.
  • Pas de tests #[ignore] : les tests de cette RFC tournent dans le suite par défaut (cargo test --features experimental-fediverse).
  • Pas de couverture HTTP/2 : Mastodon parle HTTP/1.1 ; wiremock supporte les deux mais on cible la cible commune.
  • Pas de mesure de latence : couvert par le bench Phase 5 (charge 1×1000×50, hors scope CI).

API proposée

Aucune. Les tests sont binaires sous crates/rustwarden-core/tests/fediverse_interop.rs. Ils consomment uniquement les APIs publiques existantes :

  • crate::fediverse::http_signatures::{rsa_sha256_sign, build_signature_input, parse_and_verify_cavage}
  • crate::services::actor_key_service::ActorKeyService (generate)
  • crate::services::fediverse_outbound_service::{FediverseOutboundService, OutboundDelivery, OutboundStatus}
  • crate::fediverse::http_signatures::HttpSignedDelivery (instance avec MockDatabase)

Compatibilité

Aucun impact sur les apps consommatrices : ces tests sont internes à rustwarden-core et n'exposent ni route ni type. La feature experimental-fediverse reste obligatoire (#[cfg(feature = "experimental-fediverse")] au sommet du fichier).

Alternatives

  1. Ne rien faire — rejeté : régressions silencieuses sur le format de signature passeraient le CI.
  2. Mock reqwest::Client avec mockito — rejeté : reqwest::Client n'expose pas d'injection de transport ; il faudrait passer par Builder::resolve + serveur local, ce que wiremock simplifie déjà.
  3. Lancer un Mastodon réel via testcontainers — rejeté à ce stade : démarrage 30 s+, dépendances Ruby, instabilité CI ; gardé en option future pour un binaire tests/interop_mastodon.rs #[ignore].
  4. Tester uniquement la couche pure (déjà couverte) — insuffisant : ne lève pas les bugs « signature passe localement mais reqwest envoie un header capitalisé que Mastodon rejette ».

Testing plan

Trois cas dans tests/fediverse_interop.rs :

TestComportement attendu
signed_request_round_trip_through_wiremockPOST signé reçu, Signature parsable, vérifié contre la public key locale.
outbound_delivers_when_inbox_returns_202drain_one retourne Delivered, delivered_at non-NULL.
outbound_defers_when_inbox_returns_503drain_one retourne Pending (count++) avec next_retry_at = now + 5min.

Les tests utilisent un MockDatabase SeaORM pour fixturer la users row (clés générées en RAM via ActorKeyService::generate()) et la fediverse_outbound_queue row. Pas de PostgreSQL requis.

Migration guide

Aucune. Pure addition de tests + dev-dep.

Open questions

  • Q1 : faut-il un harness réutilisable (tests/common/wiremock_inbox.rs) pour les futures RFCs interop ? Réponse provisoire : non, on attend la troisième RFC qui en aurait besoin (règle de trois).

Score (26/35)

CritèreNoteNote
Généralité4/5Tests utiles à toutes les apps consommatrices.
Stabilité API5/5Pas d'API publique modifiée.
Performance4/5wiremock ~50–100 ms par test ; négligeable en CI.
Sécurité3/5Couvre la chaîne signature mais pas les attaques (replay, tampering) — RFC distincte.
Complexité4/5Squelette de ~150 LoC + 1 dev-dep.
Maintenance3/5wiremock 0.6 stable depuis 2024 ; surface d'API minimale utilisée.
Documentation3/5Cette RFC + commentaires inline ; pas de guide séparé.