Federated collaboration — Story 3: Merge request via federation (Offer(Branch)) #13
Part of the Federated Collaboration roadmap (docs/maintainers/federation-roadmap.md). Depends on Story 1 and Story 2. This is the epic.
Goal
As a user who forked a remote repository (Story 2) and pushed a contribution branch, open a merge request against the upstream repository on the other instance, and see its outcome (accepted / rejected / merged) back on my instance.
Chosen protocol shape: fork-and-pull via Offer(Branch)
Submitter instance sends a ForgeFed Offer wrapping a Branch (or Ticket referencing a branch) to the upstream repository actor's inbox, carrying the branch fetch URL. The target instance git fetches that branch and opens a local merge request referencing it. Rationale in the roadmap doc: keeps real git objects (reviewers see real commits/diffs, can pull the branch), degrades gracefully.
Scope
- Outbound
Offer(Branch)— new activity type in ActorDocuments, enqueued via DeliveryService to the upstream repo inbox, signed by submitter Person or fork repo actor. - Inbound
OfferHandlerin ActivityDispatcher — validate,git fetchsubmitter branch (SSRF-guarded — NEW outbound git-fetch surface, security-auditor review required), create a local MR row referencing the remote branch. - Status back-channel —
Accept/Reject/merge-notify activities so the submitter sees the outcome on their instance.
Prereqs / risks
- New outbound-git-fetch attack surface (shared with Story 2). RemoteUrlGuard must cover git fetch, not just HTTP.
- Actor lifecycle (
Delete/Update) still missing — a federated MR referencing a deleted/moved remote fork goes stale silently. Consider handling as part of hardening. - Interop: scope to git-shark <-> git-shark first. Forgejo federation is early / likely incompatible.
Out of scope
- Federated review comments / inline discussion (future story).
- Patch-offer (embedded-diff) alternative protocol shape — explicitly rejected for v1 in favor of fork-and-pull.
Test-first per story: outbound Offer wire format, inbound Offer -> local MR creation, status round-trip.