Design Discussion: ActivityPub support + ForgeFed vocabulary #6602

Open
opened 2025-11-02 07:00:57 -06:00 by GiteaMirror · 23 comments
Owner

Originally created by @cjslep on GitHub (Dec 29, 2020).

#1612 discusses Federation in general but I wanted to open an issue for the ActivityPub + ForgeFed solution specifically and concretize this unit of work. Let's keep to discussing ActivityPub+ForgeFed design specifics here, and have the question "whether it should be ActivityPub+ForgeFed at all" discussed in the other issue (#1612).

Background

I work on the go-fed suite of ActivityPub related libraries, sites, and tools. So my knowledge is more centered on the AP/ForgeFed angle, but as I've only spent light amount of time with the Gitea code I'm not comfortable making the changes required, especially w/o without serious design discussions. And I'm not here to shill go-fed as being the solution, it just provides a solution, as there are reasons to pick it entirely, partly, or not at all. I'll try to keep the evangelization to a minimum and self-contained, at the very end.

(Optional, Time-Sensitive) Grant Opportunity

There is a limited-time opportunity for this work to be submitted as a grant to the NLNet folks via the NGI Search & Discovery grant (5-50k euros) or DAPSI grants (50k+ euros?). There is never a guarantee a grant will be selected to receive money, but given the slate of other Fediverse projects that have gotten funding via the NGI S&D, I think this is a great exercise. There is the possibility that the EU will extend certain NGI funding periods for further cycles, but it is not guaranteed.

Concretely, would need 1 or more Gitea community member volunteers interested in taking the lead on those. I personally am applying separately for other projects, so I don't have time / energy to push this aspect forward, but happy to provide guidance where possible.

Community Standards

I believe the ForgeFed work is still ongoing. An outcome could be that this effort allows whoever wants to help to pioneer additional ForgeFed behavior and be a voice there. Additionally, depending how Gitea embraces ActivityPub in general, it may also have opportunities to create Fediverse Enhancement Proposals, so no matter what the volunteers will definitely get open-source community leadership opportunities.

Design

Overview

ActivityPub is based on the concept of actors exchanging activities. These activities tell federated peers how to update their view of the "Federated Web", which is a linked-data graph composed of different RDF ontologies. That's a jargon-y way of saying "data types are flexible, and have pointers to other pieces of data". ForgeFed is just one ontology focusing on Forge behaviors and entities. Peers are not expected to know how to interpret every single ontology on this Federated Web, so Gitea can just focus on a narrow one -- ForgeFed -- in addition to the basic ActivityStreams vocabulary that acts as a common language.

This does not prevent Gitea from adopting different ontologies later, if the project decided to support viewing/interacting with the other kinds of activities going on in the wider web. It is just not a requirement right now, in the spirit of keeping scope limited.

The ForgeFed spec outlines the actors and the data being exchanged. A subset of that data are activites which are shareable between actors. One actor can Create a Ticket (issue) and give it to a peer, who knows: "this data -- which happens to be an activity -- is a Create so I'll invoke my create behavior/function with the payload".

So if REST is...

POST to /issues/new with the body containing payload and a session_id containing authenticated credentials. This results in invoking the server's CreateIssue function with payload based on the user calling it.

...where REST scales by just creating more endpoints and using more HTTP verbs: POST and GET and PATCH to /repo, /merge-request, /repo

Then ActivityPub is...

POST to /actors/cj/inbox with an http_signature header and Activity payload. This results in invoking the server's WhatActivityIsThis function which determines the Activity is a Create, so it calls the CreateIssue function with the rest of the payload information based on the federated_peer_user calling it.

... where ActivityPub scales by just having new types of Activities (Create, Update, Offer, etc) and new data types that are acted upon (Person, Repository, Commit, Note, etc).

This means Gitea adopting ActivityPub will require a little bit of a different philosophical mindset than perhaps is common. Rectifying that, or isolating that, with the existing codebase is a core engineering challenge.

Therefore, at a high level, Gitea would need to support the following concepts:

  • Actors
  • Sending Activities
  • Receiving Activities
  • Serving ActivityStreams
  • Fetching ActivityStreams

...then can "First Federated Behavior" be reasoned about, as a penultimate section.

Let's concretely dive into what is required to do them. The "why"s might not come together until the "Fetching ActivityStreams" section. These sections are the things I can think off of the top of my head, it may be incomplete.

Note: This only goes into S2S federation and not C2S federation

Actors

ForgeFed only has suggested guidance for actors:

  • Person
  • Project
  • Repository
  • Group/Organization/Team

To support any of these, the following would need to be tackled:

  • Conceptually, mapping Gitea's concepts ("People", "Teams") into "Actor" concepts in the ActivityPub world, and just having the community aligned with these thoughts is a big step before anything else is done.
  • Mapping Gitea's actor concepts into the ontology. "What Gitea concepts are which ActivityStreams/ForgeFed types."
  • The Actor IRIs (at what URL's peers can fetch the actor document) are arbitrary. So mapping, say, a Gitea Repository actor to a /repository/actor/{id} IRI. Note: Existing IRIs can be re-used, so long as they respect the whole Accept / Content-Type headers for ActivityStreams content.
  • "Translation layer": how to map Gitea's existing database columns into the actual fields in the ActivityStreams document to serve. I put "translation layer" in quotes, because the design could be something else.
  • A new private key generated for users. Private keys are needed for signing federating request for HTTP Signatures, if Gitea wants to use this community-adopted standard. I strongly recommend sticking to it for interoperability and dont-shave-the-yak reasons. More on this later.
  • Managing inbox and outbox ordered collections. This one is the big doozy. Each actor basically has a "sent" and "received" queue, which means:
    • Backing storage in the database
    • User self-moderation capabilities (ex: block peers, delete receiving this message, etc)
    • Admin moderation capabilities (ex: block abusive peer Gitea instances, etc)
  • (optional, but strongly recommended) managing following and followers collections for actors. In addition to the previous concerns with the inbox and outbox:
    • curating followers lists (there is an option to manually approve followers), and how to manage that for things like a "Team" or "Repository" or "Project"
    • how to follow others (involves fetching the peer actor and presenting a UI)
    • implementing the Follow and Accept/Reject flow
  • (truly optional) managing the liked collection, if a "Team" or "Project" wants to star or favorite other items seen on the Fediverse. I'm unsure what this would look like in practice, but this could be an opportunity for someone wanting to play with UI/UX to do so.

Sending Activities

Sending activities is described in the ActivityPub spec. Unfortunately, it also explicitly relies on the C2S addressing, which must be kept in mind while implementing.

This both unblocks Gitea's ability to do any federated flow in the future, but alone is insufficient to do any specific federated flow.

To keep it succinct:

  • Mapping the actors' outbox to a concrete IRI, ex: /users/{id}/outbox, from which it can serve the outbox collection.
  • Addressing ("who am I sending it to")
    • recursive unwrapping of collections (to a specified depth)
    • deduplication and self-removal
    • stripping of sensitive fields (C2S)
    • Addressing normalization ("Automatically creating a Create activity") (C2S)
    • (optional, controversial) sharedInbox, alleviates the peer server if they're a massive instance
  • Adding to the actor's Outbox (and backing datastore)
  • Transport
    • HTTPS with HTTP Signatures (recall the actor's private key in the previous section), so being able to tell "who" is delivering the activity to the peer
    • Sets headers appropriately (doubly so due to HTTP Signatures)
    • Dereferencing peer actors to get their inbox and POSTing to there. See later on Dereferencing.
    • Bounded retrying of failed deliveries (and all those messy networking considerations)
    • Admin capabilities to manage this (prevent DoSing a peer, backlogged queues, etc)
  • Inbox Forwarding
    • detecting when to do it
    • determining who to forward to

Receiving Activities

Receiving activities is the second half:

  • Mapping the actors' inbox to a concrete IRI, ex: /users/{id}/inbox, from which it can serve the inbox collection for a GET request (if desired), or receive federated peer POST requests.
  • Verification of HTTP Signatures: fetching the peer actor, getting their key information, and verifying the signature.
  • Ensure it is not blocked for some reason (admin or user level)
  • Specifying specific Gitea behavior to do as a consequence of receiving the peer's federated data
    • This is the goal to get our "First Federated Behavior" section below
    • This may change something like a federated_view table of data that is just a cached version of the peer's data (but can always be authoritatively gotten from a peer, see "Fetching ActivityStreams below")
      • Note that this would need to be manageable by an admin (ex: remove undesired content)
  • Ensuring the new Gitea state is reflected in "Serving ActivityStreams" (see next section)
    • This lets federated peers "understand" Gitea without having to do something like scraping the HTML/Javascript UI to get the information, maybe get notifications and fetch this data, etc.
  • (optional, controversial) sharedInbox support. This is a way to optimize your Gitea instance if you have thousands of users on one instance and tons of activities flying about constantly, and don't want to DoS that server instance. I personally dislike sharedInbox but won't go into those reasons here.

Serving ActivityStreams

As a consequence of the aforementioned section of "having Actors do things", they will generate data that needs to have an ActivityStreams representation so that peers, upon looking at what an actor has been up to, can natively understand what is going on. For Gitea specifically, this gets into the ForgeFed examples.

  • Mapping Gitea concepts like "commits" and "repository" to the ForgeFed definitions (or ActivityStreams definitions, too).
  • Mapping these types to IRIs, ex: /repo/{id}. Note: as before, existing IRIs can be re-used, so long as they respect the whole Accept / Content-Type headers for ActivityStreams content.
  • Having a "translation layer" to transmute the Gitea database columns into ActivityStreams data server in http.Handler. Again, "translation layer" is in quotes because there may be a better design choice.
  • Ensuring that the endpoint is protected and requires appropriate credentials to view, if applicable.

This unblocks the next bit...

Fetching ActivityStreams

If I ever use the term "dereferencing", this is what I mean.

A Gitea instance will be able to fetch a peer Gitea instance's ActivityStreams, thanks to the work outlined in the previous section. This allows you on foo.gitea.io to fetch my Person actor on bar.gitea.io but, say, render it on a webpage to yourself natively on foo.gitea.io. Dereferencing is needed for other operations, in particular the Delivery and Addressing portions of "Sending an Activity".

Fetching ActivityStreams data also allows foo.gitea.io to potentially display all the information of a Repository shown on bar.gitea.io, without having to actually navigate to bar.gitea.io. Any actions done by users would spawn new Activities and resulting in invoking the "Sending Activities" section. Again, that's up to the concrete design.

  • Transport (http.Client)
    • Optionally with HTTP signatures if a user is signed in
    • Sets the Accept header appropriately
  • The UI work to render the desired peer data types (Repository, Person, Team) in Gitea's UI

First Federated Behavior

All of the above, and we haven't yet discussed the behaviors unlocked by ForgeFed yet. They list several:

  • Reporting Pushed Commits
  • Opening a Ticket
  • Create
  • Offer
  • Commenting

I would propose just aiming for one initially. Even aiming for none of these, but doing the other sections above, is a large enough feat worth celebrating: Getting to the point where the followers flow works is a celebratory moment, if Gitea wants to have the concepts of "followers"/"following" (and I think it does?).

This first federated behavior would involve:

  • The UI/UX work to introduce that behavior/flow, if needed. Something like "Reporting Pushed Commits" might just be an additional backend effect.
  • Adding the IRI endpoint that would trigger the new behavior/flow, if needed.
  • Sending the appropriate Activity to the federated peer for that behavior, as defined by ForgeFed.
  • Designing a hook when receiving that Activity from a federated peer, as defined by Forgefed.

Whew, done. :)

Go-Fed

I promised to keep this at the end and self-contained. :) The go-fed/activity library focuses on being middleware. You implement several interfaces like Database which it will use. You then use the resulting library calls in a http.Handler to deal with "Actors sending Activities" or "serve this ActivityStreams representation".

Since it is middleware, it only solves some of the problems I listed above. Big picture, the main problems remaining unsolved by go-fed are the integration ones:

  • How to map IRIs/URLs to ActivityStreams data
  • How to map ActivityStreams data to the database

More specifically, going section-by-section and listing the bullets that are addressed by go-fed:

  • ActivityStreams
    • How to deserialize ActivityStreams JSON-LD data into a concrete Golang type. It turns out this isn't easy; struct field-tagging with json is woefully insufficient. I didn't mention this aspect at all before, but I won't dive into this unless someone wants to do so. Highly caution against deserializing ActivityStreams on one's own, go-fed/activity/streams is there to help to go from []byte to ActivityStreamsCreate. Scales across all sorts of RDF vocabularies, too.
    • This makes it easy to create and manipulate ActivityStreams data natively in Go
  • Actors
    • Handy functions simplify serving Actors, as it's just like any other ActivityStreams data. Mapping the IRIs remains the largest challenge here.
  • Sending Activities
    • The "Addressing", "Transport" and "Inbox Forwarding" bullets above are all addressed by go-fed/activity/pub
      • All sub-bullets, too! Except: sharedInbox
    • There is a separate go-fed/httpsig for HTTP Signatures signing and verifying
  • Receiving Activities
    • Upon receiving federated data, provides hook for doing that HTTP Signatures (or other) authentication
    • Provides hook to map payload to your Activity-specific behavior (Create => createFn(), etc).
    • It provides common out-of-the-box default behavior for ActivityPub specific Activity behavior (7.2-7.10), for example a peer's Create{Note} will attempt to create the federated Note via the local Database interface, to try to help make bootstrapping quicker.
  • Serving ActivityStreams
    • Handy functions simplify serving ActivityStreams, just like the Actors section mentioned above. Mapping the IRIs remains the largest challenge here.
  • Fetching ActivityStreams
    • go-fed/activity/pub provides an optional transport to dereference using HTTP signatures, but doesn't tell you how to use the resulting data nor does it have any idea what it is for.

The go-fed/activity library does not solve:

  • Managing your mapping of IRI endpoints to concepts/actors/types
  • How to actually store things in a database
  • Making sure your IRI endpoints match your database queries
  • For what reason do you want to dereference to fetch a peer's latest data or send data to a peer (it only does just enough for its own purposes and no more)
    • It can't magically "know" what ActivityStreams data you want to use -- the ability to crafting the desired Activity and objects without constraint is indeed the whole point.

Finally, some downsides of go-fed:

  • Due to code generation hundreds of thousands of lines, the binary size is large. It cannot compile on a Raspberry Pi, due to that code size.
  • There are parts of the API that are still rough. However, I am open to feedback here.
  • The tutorials are not the most intuitive. I know the go-fed.org site looks like a backend engineer wrote it, but that's being addressed as we speak.
  • Implementing the interfaces can be unclear at times. However, I need to hear the questions, to better change the interfaces and/or fix unhelpful/unclear comments.
  • Gitea would be the first (other than me & my blogs/pet-projects) to adopt go-fed/activity/pub, which comes with its own risks. WriteFreely uses go-fed/activity/streams.

I hope this kicks off a productive discussion. Thanks for reading this far, if you made it. :)

Originally created by @cjslep on GitHub (Dec 29, 2020). #1612 discusses Federation in general but I wanted to open an issue for the ActivityPub + ForgeFed solution specifically and concretize this unit of work. Let's keep to discussing ActivityPub+ForgeFed design specifics here, and have the question "whether it should be ActivityPub+ForgeFed at all" discussed in the other issue (#1612). # Background I work on the go-fed suite of ActivityPub related libraries, sites, and tools. So my knowledge is more centered on the AP/ForgeFed angle, but as I've only spent light amount of time with the Gitea code I'm not comfortable making the changes required, especially w/o without serious design discussions. And I'm not here to shill go-fed as being *the* solution, it just provides *a* solution, as there are reasons to pick it entirely, partly, or not at all. I'll try to keep the evangelization to a minimum and self-contained, at the very end. ## (Optional, Time-Sensitive) Grant Opportunity There is a limited-time opportunity for this work to be submitted as a grant to the NLNet folks via the [NGI Search & Discovery](https://nlnet.nl/discovery/guideforapplicants/) grant (5-50k euros) or [DAPSI](https://dapsi.ngi.eu/apply/) grants (50k+ euros?). There is never a guarantee a grant will be selected to receive money, but given the slate of other Fediverse projects that *have* gotten funding via the NGI S&D, I think this is a great exercise. There is the possibility that the EU will extend certain NGI funding periods for further cycles, but it is not guaranteed. Concretely, would need 1 or more Gitea community member volunteers interested in taking the lead on those. I personally am applying separately for other projects, so I don't have time / energy to push this aspect forward, but happy to provide guidance where possible. ## Community Standards I believe the ForgeFed work is still ongoing. An outcome could be that this effort allows whoever wants to help to pioneer additional [ForgeFed behavior](https://forgefed.peers.community/behavior.html) and be a voice [there](https://talk.feneas.org/c/forgefed/10). Additionally, depending how Gitea embraces ActivityPub in general, it may also have opportunities to create [Fediverse Enhancement Proposals](https://socialhub.activitypub.rocks/t/fep-a4ed-the-fediverse-enhancement-proposal-process/1171), so no matter what the volunteers will definitely get open-source community leadership opportunities. # Design ## Overview ActivityPub is based on the concept of *actors* exchanging *activities*. These activities tell federated peers how to update their view of the "Federated Web", which is a linked-data graph composed of different RDF ontologies. That's a jargon-y way of saying "data types are flexible, and have pointers to other pieces of data". ForgeFed is just one ontology focusing on Forge behaviors and entities. Peers are not expected to know how to interpret every single ontology on this Federated Web, so Gitea can just focus on a narrow one -- ForgeFed -- in addition to the basic ActivityStreams vocabulary that acts as a common language. This does not prevent Gitea from adopting different ontologies later, if the project decided to support viewing/interacting with the other kinds of *activities* going on in the wider web. It is just not a requirement right now, in the spirit of keeping scope limited. The [ForgeFed](https://forgefed.peers.community/behavior.html#actors) spec outlines the *actors* and the *data* being exchanged. A subset of that data are *activites* which are shareable between actors. One actor can `Create` a `Ticket` (issue) and give it to a peer, who knows: "this *data* -- which happens to be an activity -- is a `Create` so I'll invoke my *create* behavior/function with the payload". *So if REST is*... `POST` to `/issues/new` with the body containing `payload` and a `session_id` containing authenticated credentials. This results in invoking the server's `CreateIssue` function with `payload` based on the `user` calling it. ...where REST scales by just creating more endpoints and using more HTTP verbs: `POST` and `GET` and `PATCH` to `/repo`, `/merge-request`, `/repo` *Then ActivityPub is*... `POST` to `/actors/cj/inbox` with an `http_signature` header and Activity `payload`. This results in invoking the server's `WhatActivityIsThis` function which determines the Activity is a `Create`, so it calls the `CreateIssue` function with the rest of the `payload` information based on the `federated_peer_user` calling it. ... where ActivityPub scales by just having new types of Activities (`Create`, `Update`, `Offer`, etc) and new data types that are acted upon (`Person`, `Repository`, `Commit`, `Note`, etc). This means Gitea adopting ActivityPub will require a little bit of a different philosophical mindset than perhaps is common. Rectifying that, or isolating that, with the existing codebase is a core engineering challenge. Therefore, at a high level, Gitea would need to support the following concepts: - Actors - Sending Activities - Receiving Activities - Serving ActivityStreams - Fetching ActivityStreams ...then can "First Federated Behavior" be reasoned about, as a penultimate section. Let's concretely dive into what is required to do them. The "why"s might not come together until the "Fetching ActivityStreams" section. These sections are the things I can think off of the top of my head, it may be incomplete. *Note: This only goes into S2S federation and not C2S federation* ## Actors ForgeFed only has [suggested guidance](https://forgefed.peers.community/behavior.html#actors) for actors: - `Person` - `Project` - `Repository` - `Group`/`Organization`/`Team` To support any of these, the following would need to be tackled: - Conceptually, mapping Gitea's concepts ("People", "Teams") into "Actor" concepts in the ActivityPub world, and just having the community aligned with these thoughts is a big step before anything else is done. - Mapping Gitea's actor concepts into the ontology. "What Gitea concepts are which ActivityStreams/ForgeFed types." - The Actor IRIs (at what URL's peers can fetch the actor document) are arbitrary. So mapping, say, a Gitea Repository actor to a `/repository/actor/{id}` IRI. Note: Existing IRIs can be re-used, so long as they respect the whole `Accept` / `Content-Type` headers for ActivityStreams content. - "Translation layer": how to map Gitea's existing database columns into the actual fields in the ActivityStreams document to serve. I put "translation layer" in quotes, because the design could be something else. - A new private key generated for users. Private keys are needed for signing federating request for HTTP Signatures, *if* Gitea wants to use this community-adopted standard. I strongly recommend sticking to it for interoperability and dont-shave-the-yak reasons. More on this later. - Managing `inbox` and `outbox` ordered collections. This one is the big doozy. Each actor basically has a "sent" and "received" queue, which means: - Backing storage in the database - User self-moderation capabilities (ex: block peers, delete receiving this message, etc) - Admin moderation capabilities (ex: block abusive peer Gitea instances, etc) - (optional, but strongly recommended) managing `following` and `followers` collections for actors. In addition to the previous concerns with the `inbox` and `outbox`: - curating followers lists (there is an option to manually approve followers), and how to manage that for things like a "Team" or "Repository" or "Project" - how to follow others (involves fetching the *peer* actor and presenting a UI) - implementing the `Follow` and `Accept`/`Reject` flow - (truly optional) managing the `liked` collection, if a "Team" or "Project" wants to star or favorite other items seen on the Fediverse. I'm unsure what this would look like in practice, but this could be an opportunity for someone wanting to play with UI/UX to do so. ## Sending Activities Sending activities is described in the [ActivityPub spec](https://www.w3.org/TR/activitypub/#delivery). Unfortunately, it also explicitly relies on the [C2S](https://www.w3.org/TR/activitypub/#client-addressing) addressing, which must be kept in mind while implementing. This both unblocks Gitea's ability to do *any* federated flow in the future, but alone is insufficient to do any specific federated flow. To keep it succinct: - Mapping the actors' `outbox` to a concrete IRI, ex: `/users/{id}/outbox`, from which it can serve the outbox collection. - Addressing ("who am I sending it to") - recursive unwrapping of collections (to a specified depth) - deduplication and self-removal - stripping of sensitive fields (C2S) - Addressing normalization ("Automatically creating a `Create` activity") (C2S) - (optional, controversial) `sharedInbox`, alleviates the peer server if they're a massive instance - Adding to the actor's Outbox (and backing datastore) - Transport - HTTPS with HTTP Signatures (recall the actor's private key in the previous section), so being able to tell "who" is delivering the activity to the peer - Sets headers appropriately (doubly so due to HTTP Signatures) - Dereferencing peer actors to get their `inbox` and `POST`ing to there. See later on Dereferencing. - Bounded retrying of failed deliveries (and all those messy networking considerations) - Admin capabilities to manage this (prevent DoSing a peer, backlogged queues, etc) - Inbox Forwarding - detecting when to do it - determining who to forward to ## Receiving Activities Receiving activities is the second half: - Mapping the actors' `inbox` to a concrete IRI, ex: `/users/{id}/inbox`, from which it can serve the inbox collection for a `GET` request (if desired), or receive federated peer `POST` requests. - Verification of HTTP Signatures: fetching the peer actor, getting their key information, and verifying the signature. - Ensure it is not blocked for some reason (admin or user level) - **Specifying specific Gitea behavior to do as a consequence of receiving the peer's federated data** - This is the goal to get our "First Federated Behavior" section below - This may change something like a `federated_view` table of data that is just a cached version of the peer's data (but can always be authoritatively gotten from a peer, see "Fetching ActivityStreams below") - Note that this would need to be manageable by an admin (ex: remove undesired content) - Ensuring the new Gitea state is reflected in "Serving ActivityStreams" (see next section) - This lets federated peers "understand" Gitea without having to do something like scraping the HTML/Javascript UI to get the information, maybe get notifications and fetch this data, etc. - (optional, controversial) `sharedInbox` support. This is a way to optimize your Gitea instance if you have thousands of users on one instance and tons of activities flying about constantly, and don't want to DoS that server instance. I personally dislike `sharedInbox` but won't go into those reasons here. ## Serving ActivityStreams As a consequence of the aforementioned section of "having Actors do things", they will generate data that needs to have an ActivityStreams representation so that peers, upon looking at what an actor has been up to, can natively understand what is going on. For Gitea specifically, this gets into the [ForgeFed examples](https://forgefed.peers.community/modeling.html#repository). - Mapping Gitea concepts like "commits" and "repository" to the [ForgeFed definitions](https://forgefed.peers.community/modeling.html) (or ActivityStreams definitions, too). - Mapping these types to IRIs, ex: `/repo/{id}`. Note: as before, existing IRIs can be re-used, so long as they respect the whole `Accept` / `Content-Type` headers for ActivityStreams content. - Having a "translation layer" to transmute the Gitea database columns into ActivityStreams data server in `http.Handler`. Again, "translation layer" is in quotes because there may be a better design choice. - Ensuring that the endpoint is protected and requires appropriate credentials to view, if applicable. This unblocks the next bit... ## Fetching ActivityStreams *If I ever use the term "dereferencing", this is what I mean*. A Gitea instance will be able to fetch a peer Gitea instance's ActivityStreams, thanks to the work outlined in the previous section. This allows you on `foo.gitea.io` to fetch my `Person` actor on `bar.gitea.io` but, say, render it on a webpage to yourself natively on `foo.gitea.io`. Dereferencing is needed for other operations, in particular the Delivery and Addressing portions of "Sending an Activity". Fetching ActivityStreams data also allows `foo.gitea.io` to potentially display all the information of a Repository shown on `bar.gitea.io`, without having to actually navigate to `bar.gitea.io`. Any actions done by users would spawn new Activities and resulting in invoking the "Sending Activities" section. Again, that's up to the concrete design. - Transport (`http.Client`) - Optionally with HTTP signatures if a user is signed in - Sets the `Accept` header appropriately - The UI work to render the desired peer data types (`Repository`, `Person`, `Team`) in Gitea's UI ## First Federated Behavior All of the above, and we haven't yet discussed the behaviors unlocked by ForgeFed yet. They [list several](https://forgefed.peers.community/behavior.html#server-to-server-interactions): - Reporting Pushed Commits - Opening a Ticket - Create - Offer - Commenting I would propose just aiming for *one* initially. Even aiming for *none* of these, but doing the other sections above, is a large enough feat worth celebrating: Getting to the point where the followers flow works is a celebratory moment, *if* Gitea wants to have the concepts of "followers"/"following" (and I think it does?). This first federated behavior would involve: - The UI/UX work to introduce that behavior/flow, if needed. Something like "Reporting Pushed Commits" might just be an additional backend effect. - Adding the IRI endpoint that would trigger the new behavior/flow, if needed. - Sending the appropriate Activity to the federated peer for that behavior, as defined by ForgeFed. - Designing a hook when *receiving* that Activity from a federated peer, as defined by Forgefed. Whew, done. :) ## Go-Fed I promised to keep this at the end and self-contained. :) The `go-fed/activity` library focuses on being middleware. You implement several interfaces like `Database` which it will use. You then use the resulting library calls in a `http.Handler` to deal with "Actors sending Activities" or "serve this ActivityStreams representation". Since it is middleware, it only solves *some* of the problems I listed above. Big picture, the main problems remaining unsolved by go-fed are the integration ones: - How to map IRIs/URLs to ActivityStreams data - How to map ActivityStreams data to the database More specifically, going section-by-section and listing the bullets that are addressed by `go-fed`: - ActivityStreams - How to deserialize ActivityStreams JSON-LD data into a concrete Golang type. It turns out this isn't easy; struct field-tagging with `json` is woefully insufficient. I didn't mention this aspect at all before, but I won't dive into this unless someone wants to do so. Highly caution *against* deserializing ActivityStreams on one's own, `go-fed/activity/streams` is there to help to go from `[]byte` to `ActivityStreamsCreate`. Scales across all sorts of RDF vocabularies, too. - This makes it easy to create and manipulate ActivityStreams data natively in Go - Actors - Handy functions simplify serving Actors, as it's just like any other ActivityStreams data. Mapping the IRIs remains the largest challenge here. - Sending Activities - The "Addressing", "Transport" and "Inbox Forwarding" bullets above are all addressed by `go-fed/activity/pub` - All sub-bullets, too! Except: `sharedInbox` - There is a separate `go-fed/httpsig` for HTTP Signatures signing and verifying - Receiving Activities - Upon receiving federated data, provides hook for doing that HTTP Signatures (or other) authentication - Provides hook to map `payload` to your Activity-specific behavior (`Create => createFn()`, etc). - It provides common out-of-the-box default behavior for [ActivityPub specific](https://www.w3.org/TR/activitypub/#create-activity-inbox) Activity behavior (7.2-7.10), for example a peer's `Create{Note}` will attempt to create the federated `Note` via the local `Database` interface, to try to help make bootstrapping quicker. - Serving ActivityStreams - Handy functions simplify serving ActivityStreams, just like the Actors section mentioned above. Mapping the IRIs remains the largest challenge here. - Fetching ActivityStreams - `go-fed/activity/pub` provides an optional transport to dereference using HTTP signatures, but doesn't tell you how to use the resulting data nor does it have any idea what it is for. The `go-fed/activity` library does **not** solve: - Managing your mapping of IRI endpoints to concepts/actors/types - How to actually store things in a database - Making sure your IRI endpoints match your database queries - *For what reason* do you want to dereference to fetch a peer's latest data or send data to a peer (it only does just enough for its own purposes and no more) - It can't magically "know" what ActivityStreams data you want to use -- the ability to crafting the desired Activity and objects without constraint is indeed the whole point. Finally, some downsides of `go-fed`: - Due to code generation hundreds of thousands of lines, the binary size is *large*. It cannot compile on a Raspberry Pi, due to that code size. - There are parts of the API that are still rough. However, I am open to feedback here. - The tutorials are not the most intuitive. I know the go-fed.org site looks like a backend engineer wrote it, but that's being addressed as we speak. - Implementing the interfaces can be unclear at times. However, I need to hear the questions, to better change the interfaces and/or fix unhelpful/unclear comments. - Gitea would be the first (other than me & my blogs/pet-projects) to adopt `go-fed/activity/pub`, which comes with its own risks. WriteFreely uses `go-fed/activity/streams`. I hope this kicks off a productive discussion. Thanks for reading this far, if you made it. :)
GiteaMirror added the type/proposaltopic/federation labels 2025-11-02 07:00:57 -06:00
Author
Owner

@cjslep commented on GitHub (Dec 31, 2020):

I also opened a discussion on Forgefed where Bill helpfully pointed out I did not reference #9045. That issue is locked to collaborators so I am not able to post there, but I think a lot of the technical discussion over there is relevant to this issue, so please check it out.

Wishing everyone a happy New Year and guten Rutsch ins neue Jahr!

@cjslep commented on GitHub (Dec 31, 2020): I also opened a [discussion on Forgefed](https://talk.feneas.org/t/gitea-activitypub-forgefed/364) where Bill helpfully pointed out I did not reference #9045. That issue is locked to collaborators so I am not able to post there, but I think a lot of the technical discussion over there is relevant to this issue, so please check it out. Wishing everyone a happy New Year and guten Rutsch ins neue Jahr!
Author
Owner

@pilou- commented on GitHub (Jul 7, 2021):

Posted on behalf of Loic, as explained in the post scriptum (original message on the Fedeproxy forum).


Bonjour,

TL;DR: what would it take to put federation on the Gitea 1.16.x roadmap?

The gitea roadmap for 1.1.15 is now locked and the next release cycle will start right after it is released. However the roadmap for 1.1.16 does not include the implementation of ActivityPub.

What would it take to make that happen?

It is of course a matter of who is interested to implement it and has time and skills to actually do it. An area where the fedeproxy project could help by redirecting 5,000€ of its funds (total 75K€). This is not much but it's not nothing and could be used to make the first baby step(s).

It is also a matter of defining the first baby steps that would lead Gitea in the direction of federation. At the moment there only is a very high level discussion that can hardly be translated into actionable items. In your expert opinion, what would be the first minimal tasks that would make most sense?

Cheers

P.S: I'm very motivated to help move forward and in case you're curious why I don't post myself (thank you Pierre-Louis for being my proxy :-) ), feel free to read why I deleted my GItHub account a few years ago.

@pilou- commented on GitHub (Jul 7, 2021): Posted on behalf of [Loic](https://mastodon.online/@dachary), as explained in the post scriptum ([original message on the Fedeproxy forum](https://forum.fedeproxy.eu/t/advancing-federation-in-gitea/240/2)). <hr> Bonjour, TL;DR: what would it take to put federation on [the Gitea 1.16.x roadmap](https://github.com/go-gitea/gitea/milestone/93)? The [gitea roadmap for 1.1.15](https://github.com/go-gitea/gitea/issues/14477) is [now locked](https://github.com/go-gitea/gitea/issues/14477#issuecomment-854395920) and the next [release cycle](https://github.com/go-gitea/gitea/blob/main/CONTRIBUTING.md#release-cycle) will start right after it is released. However the [roadmap for 1.1.16](https://github.com/go-gitea/gitea/milestone/93) does not include [the implementation of ActivityPub](https://github.com/go-gitea/gitea/issues/14186). What would it take to make that happen? It is of course a matter of who is interested to implement it and has time and skills to actually do it. An area where the [fedeproxy project](https://fedeproxy.eu) could help by redirecting 5,000€ of [its funds (total 75K€)](https://forum.fedeproxy.eu/t/about-the-funding-category/19). This is not much but it's not nothing and could be used to make the first baby step(s). It is also a matter of defining the first baby steps that would lead Gitea in the direction of federation. At the moment there only is [a very high level discussion](https://github.com/go-gitea/gitea/issues/14186) that can hardly be translated into actionable items. In your expert opinion, what would be the first minimal tasks that would make most sense? Cheers P.S: I'm very motivated to help move forward and in case you're curious why I don't post myself (thank you Pierre-Louis for being my proxy :-) ), feel free to read [why I deleted my GItHub account a few years ago](https://blog.dachary.org/2018/07/29/why-i-deleted-my-github-account/).
Author
Owner

@techknowlogick commented on GitHub (Jul 7, 2021):

I should note that Loic had reached out to me (and likely a few other forge maintainers) about this in the past via email, and I apologize for not responding. To quote Jeff Goldblum, life uhh.. gets in the way (I know this isn't the actual quote)

the next release cycle will start right after it is released.

Technically 1.16.x work has already started, but that's due to the feature freeze with 1.15.x. Although the sooner a PR is created the more likely it is to get into the 1.16.x milestone (see note about creating the PR below).

What would it take to make that happen?

To be frank, it's a matter of finding a developer to work on this (be it a maintainer of Gitea, or someone from outside the project). As you do have funding, I suspect that might be easier, as in the past few months over 1K USD has been collected as bounties working on various PRs (I personally have put up some funds as bounties). So there are developers who would likely be willing (and capable) to take on this work. If you were to use these funds I would recommend giving them directly to the developer working on this PR, and the maintainers reviewing it, rather than to the project itself (although of course speaking on behalf of the project we'd be happy/thankful to accept funds, but donations to the project don't necessarily guarantee that specific tasks would be completed).

A note: as this is likely a large PR, I recommend the developer who works on it first discuss the approach of integrating this into gitea with the project (this is to prevent a large PR from being completed and perhaps some foundational work of the PR would be suggested to be done differently, so the developer would then potentially need to change a significant amount of it).

cc: @KN4CK3R and @adelowo in case you'd be interested in paid work on Gitea

@techknowlogick commented on GitHub (Jul 7, 2021): I should note that Loic had reached out to me (and likely a few other forge maintainers) about this in the past via email, and I apologize for not responding. To quote Jeff Goldblum, life uhh.. gets in the way (I know this isn't the actual quote) > the next release cycle will start right after it is released. Technically 1.16.x work has already started, but that's due to the feature freeze with 1.15.x. Although the sooner a PR is created the more likely it is to get into the 1.16.x milestone (see note about creating the PR below). > What would it take to make that happen? To be frank, it's a matter of finding a developer to work on this (be it a maintainer of Gitea, or someone from outside the project). As you do have funding, I suspect that might be easier, as in the past few months over 1K USD has been collected as bounties working on various PRs (I personally have put up some funds as bounties). So there are developers who would likely be willing (and capable) to take on this work. If you were to use these funds I would recommend giving them directly to the developer working on this PR, and the maintainers reviewing it, rather than to the project itself (although of course speaking on behalf of the project we'd be happy/thankful to accept funds, but donations to the project don't necessarily guarantee that specific tasks would be completed). A note: as this is likely a large PR, I recommend the developer who works on it first discuss the approach of integrating this into gitea with the project (this is to prevent a large PR from being completed and perhaps some foundational work of the PR would be suggested to be done differently, so the developer would then potentially need to change a significant amount of it). cc: @KN4CK3R and @adelowo in case you'd be interested in paid work on Gitea
Author
Owner

@aschrijver commented on GitHub (Jul 9, 2021):

FYI. On fediverse this recent development was enthusiastically shared and on Lemmy (a federated Reddit) a core dev said they'd move issue tracking from Github with this in place, while someone else said 'where can I donate?'.

This last bit is not really clear, plus there may be additional opportunities to get more funding to realize this functionality. And also ForgeFed may still have funds available.

@aschrijver commented on GitHub (Jul 9, 2021): FYI. On fediverse this recent development was [enthusiastically shared](https://mastodon.social/@humanetech/106544430567239842) and on Lemmy (a federated Reddit) a [core dev said](https://lemmy.ml/post/73411/comment/65922) they'd move issue tracking from Github with this in place, while someone else said ['where can I donate?'](https://lemmy.ml/post/73411/comment/65933). This last bit [is not really clear](https://forum.fedeproxy.eu/t/advancing-federation-in-gitea/240/7), plus there may be [additional opportunities to get more funding](https://socialhub.activitypub.rocks/t/grant-proposal-for-federation-in-gitea/1921) to realize this functionality. And also ForgeFed [may still have funds available](https://talk.feneas.org/t/good-forgefed-news-but-website-is-down/402).
Author
Owner

@pilou- commented on GitHub (Jul 9, 2021):

Posted on behalf of Loic.


@techknowlogick thanks for your reply and guidance :-) It's good to know the timing is right and I'm hopeful someone will be interested.

you were to use these funds I would recommend giving them directly to the developer working on this PR, and the maintainers reviewing it, rather than to the project itself

I'll follow your advice. Since fedeproxy is horizontal (no organization) the funds originate from individuals (Pierre-Louis and myself, 50% each) and it will be possible to pay the person(s) doing the work directly.

as this is likely a large PR...

Maybe it can be broken down in smaller tasks / PRs? It would be easier to review and implement. And it will also be easier to prioritize which task should be worked on first and which ones can fit is the modest budget there is.

@pilou- commented on GitHub (Jul 9, 2021): Posted on behalf of [Loic](https://forum.fedeproxy.eu/t/advancing-federation-in-gitea/240/5). <hr> @techknowlogick thanks for your reply and guidance :-) It's good to know the timing is right and I'm hopeful someone will be interested. > you were to use these funds I would recommend giving them directly to the developer working on this PR, and the maintainers reviewing it, rather than to the project itself I'll follow your advice. Since fedeproxy is horizontal (no organization) the funds originate from individuals (Pierre-Louis and myself, 50% each) and it will be possible to pay the person(s) doing the work directly. > as this is likely a large PR... Maybe it can be broken down in smaller tasks / PRs? It would be easier to review and implement. And it will also be easier to prioritize which task should be worked on first and which ones can fit is the modest budget there is.
Author
Owner

@cjslep commented on GitHub (Jul 18, 2021):

There was a small meeting today between zeripath, myself, and Loic around building towards a future where federation work has a grant fund people to do it (to be clear: not necessarily funding us three, it could be funding one or two of us + others in the community). On the socialhub was the agenda. In the interest of transparency, the meeting was recorded which should also shortly be available there as well.

Since the scope of work is fairly large and the goals rather ambitious, we definitely want to be as transparent as possible w/ the wider Gitea community and welcome folks to feel free to step up & participate if you, dear reader, would like.

@cjslep commented on GitHub (Jul 18, 2021): There was a small meeting today between zeripath, myself, and Loic around building towards a future where federation work has a grant fund people to do it (to be clear: not necessarily funding us three, it could be funding one or two of us + others in the community). On the [socialhub](https://socialhub.activitypub.rocks/t/grant-proposal-for-federation-in-gitea/1921/10?u=cjs) was the agenda. In the interest of transparency, the meeting was recorded which should also shortly be available there as well. Since the scope of work is fairly large and the goals rather ambitious, we definitely want to be as transparent as possible w/ the wider Gitea community and welcome folks to feel free to step up & participate if you, dear reader, would like.
Author
Owner

@lunny commented on GitHub (Jul 18, 2021):

If somebody want to start the work from v1.16, it's a good start point to add comment on #16429 .

@lunny commented on GitHub (Jul 18, 2021): If somebody want to start the work from v1.16, it's a good start point to add comment on #16429 .
Author
Owner

@aschrijver commented on GitHub (Jul 18, 2021):

Watch this interesting talk about funding, grants and more technical background information (published with PeerTube: federated video streaming) between @dachary (of FedeProxy project), @cjslep (of GoFed project) and @zeripath (Gitea maintainer).

@aschrijver commented on GitHub (Jul 18, 2021): Watch this interesting [talk about funding, grants and more technical background information](https://bittube.video/videos/watch/e1886775-c7ba-4b3e-bcf7-91cdc297e728) (published with PeerTube: federated video streaming) between [@dachary](https://mastodon.online/@dachary) (of [FedeProxy](https://fedeproxy.eu) project), @cjslep (of [GoFed](https://go-fed.org) project) and @zeripath (Gitea maintainer).
Author
Owner

@pilou- commented on GitHub (Jul 22, 2021):

Posted on behalf of Loic


Bonjour,

While working on the grant application today, I ran into a question that is probably worth discussing before moving forward. Go-fed is AGPLv3+, and Gitea is MIT. Adding Go-fed as a dependency of Gitea means that Gitea, as a whole (meaning Gitea+Go-fed+other dependencies), can only be released under the AGPLv3+. Or not released at all.

To be more precise, here is the minimal set of actions required to distribute a gitea executable that contains Go-fed:

  • The https://github.com/go-gitea/gitea repository needs no change
  • A license notice stating the executable is under the AGPLv3+ license must be prominently added to the user interface (e.g. added at the beginning of js/licenses.txt)

This is not the only possible course of action, only the simplest.

What do people think about this?

@pilou- commented on GitHub (Jul 22, 2021): Posted on behalf of [Loic](https://forum.fedeproxy.eu/t/advancing-federation-in-gitea/240/13) <hr> Bonjour, <br><br> While working on the grant application today, I ran into a question that is probably worth discussing before moving forward. [Go-fed is AGPLv3+](https://github.com/go-fed/apcore/blob/master/LICENSE), and [Gitea is MIT](https://github.com/go-gitea/gitea/blob/main/LICENSE). Adding Go-fed as a dependency of Gitea means that Gitea, as a whole (meaning Gitea+Go-fed+other dependencies), can only be released under the AGPLv3+. Or not released at all. To be more precise, here is the minimal set of actions required to distribute a gitea executable that contains Go-fed: * The https://github.com/go-gitea/gitea repository needs **no** change * A license notice stating the executable is under the AGPLv3+ license must be prominently added to the user interface (e.g. added at the beginning of js/licenses.txt) This is not the only possible course of action, only the simplest. What do people think about this?
Author
Owner

@zeripath commented on GitHub (Jul 22, 2021):

Damn that makes integrating go-fed not possible.

@zeripath commented on GitHub (Jul 22, 2021): Damn that makes integrating go-fed not possible.
Author
Owner

@csolisr commented on GitHub (Jul 22, 2021):

Slight correction: The implementation of APCore is what is licensed AGPL, which is itself an extension of the standalone Go-Fed Activity libraries, which are licensed under the BSD 3-clause license instead. So what we would have to do would be to reimplement at least the relevant parts of APCore.

@csolisr commented on GitHub (Jul 22, 2021): Slight correction: The implementation of APCore is what is licensed AGPL, which is itself an extension of [the standalone Go-Fed Activity libraries](https://github.com/go-fed/activity), which are [licensed under the BSD 3-clause license instead](https://github.com/go-fed/activity/blob/master/LICENSE). So what we would have to do would be to reimplement at least the relevant parts of [APCore](https://github.com/go-fed/apcore).
Author
Owner

@aschrijver commented on GitHub (Jul 23, 2021):

I think there's no real issue here, as apcore is meant as the opinionated batteries-included server framework you'd use when creating a stand-alone AP server and save you a bunch of work. Since this issue was created, a new AP server project GoToSocial was created with Go-Fed and they chose to build on top of go-fed/activity and go-fed/httpsig, not apcore. This is what Gitea would also need to do, as @csolisr states.

Note that both @cjslep and @tsmethurst (of GoToSocial) can be found in the Go-Fed Matrix chatroom at https://matrix.to/#/#go-fed:feneas.org

@aschrijver commented on GitHub (Jul 23, 2021): I think there's no real issue here, as apcore is meant as the opinionated batteries-included server framework you'd use when creating a stand-alone AP server and save you a bunch of work. Since this issue was created, a new AP server project [GoToSocial](https://github.com/superseriousbusiness/gotosocial) was created with [Go-Fed](https://go-fed.org) and they chose to build on top of `go-fed/activity` and `go-fed/httpsig`, not apcore. This is what Gitea would also need to do, as @csolisr states. Note that both @cjslep and @tsmethurst (of GoToSocial) can be found in the Go-Fed Matrix chatroom at https://matrix.to/#/#go-fed:feneas.org
Author
Owner

@pilou- commented on GitHub (Jul 23, 2021):

Posted on behalf of Loic


Oh… my bad, thanks for the clarification!

@pilou- commented on GitHub (Jul 23, 2021): Posted on behalf of [Loic](https://forum.fedeproxy.eu/t/advancing-federation-in-gitea/240/17) <hr> Oh… my bad, thanks for the clarification!
Author
Owner

@cjslep commented on GitHub (Jul 24, 2021):

I want to confirm what @aschrijver said. go-fed/activity and other low-level libraries are intended to be as permissive as possible, as they are narrowly scoped in implementing ActivityStreams and ActivityPub. (I licensed it permissively because I believe protocol implementations should be without any "gotchas", whether for proprietary use or for free-as-in-liberty use or for ... etc. For ex: at one point write.as may have been using this library, there's no problem with that).

The go-fed/apcore package builds on top of that to make a heavily opinionated server framework that is intended for new projects that use ActivityStreams internally as fundamental database structures. On technical merit alone, I do not recommend it for Gitea in the slightest. Since it is more than just a protocol implementation and is meant to bootstrap user-facing applications, I licensed it in the spirit of GPL to give an advantage to applications that are free-as-in-liberty.

I think Gitea's infrastructure is sufficiently different from APCore that there's nothing really lost by not using it. Since they have different technical approaches, I think Gitea's integration with go-fed/activity will look very different than anything in APCore anyway, so there's not much being missed out on.

@cjslep commented on GitHub (Jul 24, 2021): I want to confirm what @aschrijver said. `go-fed/activity` and other low-level libraries are intended to be as permissive as possible, as they are narrowly scoped in implementing ActivityStreams and ActivityPub. (I licensed it permissively because I believe protocol implementations should be without any "gotchas", whether for proprietary use or for free-as-in-liberty use or for ... etc. For ex: at one point write.as may have been using this library, there's no problem with that). The `go-fed/apcore` package builds on top of that to make a heavily opinionated server framework that is intended for new projects that use ActivityStreams internally as fundamental database structures. On technical merit alone, I do **not** recommend it for Gitea in the slightest. Since it is more than just a protocol implementation and is meant to bootstrap user-facing applications, I licensed it in the spirit of GPL to give an advantage to applications that are free-as-in-liberty. I think Gitea's infrastructure is sufficiently different from APCore that there's nothing really lost by not using it. Since they have different technical approaches, I think Gitea's integration with `go-fed/activity` will look very different than anything in APCore anyway, so there's not much being missed out on.
Author
Owner

@DanielMowitz commented on GitHub (Jul 26, 2021):

In the last few weeks I looked throught the initial comment in this issue and tried to create a plan outlining what the implementation of ForgeFed could look like. The idea was to aid the discussion of the actual code that needs to be written, and not to have a 100% correct roadmap. I hope my proposals are at least somewhat sensible, as I do not have too much experience with either AP/ForgeFed or the Gitea codebase.

Mapping ForgeFed concepts to Gitea

By comparing the ForgeFed Actor guidance to Giteas modules, I came to the conclusion that the following mapping should be reasonable:

AP Gitea
Person User
Project Project
Repository Repo
Group/Organization/Team Org, Team

Preparing the data model

All modules mentioned in the table above should have the following fields added:

  • Origin IRI
  • Signing private key
  • Inbox and Outbox arrays
  • Possibly followers and following arrays
    • As far as I could tell, currently each Follow is a seperate object in the Database and the collections are created ad-hoc by iterating over them and checking the user IDs (at least for users)
  • Array of blocked users
    • This might be omitted for repos and/or projects since it makes little sense for these actors

An instance-wide list of federated/blocked instances needs to be added to the database aswell.

The "translation layer" mentioned by @cjslep should be rather straightforward, as the forgefed spec is minimal and gitea has most of the fields already. Some things like "Description" -> "summary" need to be kept in mind though.

Implementing ActivityPub behaviour

From this point onward there are two possible routes:

Implementing it all by hand

When not using a library to abstract the ActivityPub functions, this would be my proposed way of adding federated behaviour to Gitea:

  • Define an actor interface that contains functions for the following tasks:

    • Accessing the In- and Outbox
    • Returning the Followers collection
    • Returning the origin IRI of the actor
    • Returning the json representation of the actor
  • Add a new router for serving In- and Outboxes

    • The Inbox route needs to receive POST requests and create Activity objects to put into the actors inbox
    • The Outbox route needs to create POST requests from the Activity objects found in the actors outbox and also serve them on receiving a GET request
  • Create a module that prepares and sends/receives AP activities. It needs to do the following:

    • Stripping of bcc, deduplication etc. for outbound messages
    • Checking blocked status and possible forwarding for inbound messages
    • Sign outgoing and verify the signature of incoming messages (this is optional but a very good idea)
    • Implement bounded retrying, exponential backoff and ratelimiting
    • Update the local version of the actors accordingly

The following is an example of a repos json representation:

{
    "@context": [
        "https://www.w3.org/ns/activitystreams",
        "https://w3id.org/security/v1",
        "https://forgefed.peers.community/ns"
    ],
    "id": "https://dev.example/aviva/treesim",
    "type": "Repository",
    "publicKey": {
        "id": "https://dev.example/aviva/treesim#main-key",
        "owner": "https://dev.example/aviva/treesim",
        "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhki....."
    },
    "inbox": "https://dev.example/aviva/treesim/inbox",
    "outbox": "https://dev.example/aviva/treesim/outbox",
    "followers": "https://dev.example/aviva/treesim/followers",
    "team": "https://dev.example/aviva/treesim/team",
    "name": "Tree Growth 3D Simulation",
    "summary": "<p>Tree growth 3D simulator for my nature exploration game</p>"
}

Using Go-Fed

The equivalent of writing an actor interface would be implementing the db interface from go-fed. The other two points would then be met by implementing the FederatingProtocol for all actor classes (http signing is possible using go-fed/httpsig).

Fetching ActivityStreams

In whatever way it is implemented, at this point Gitea would be able to send and receive Activities as they happen, but it would be nice to also see all the Actors and their activities that came before. To do this, Gitea would have to do the following when a user requests Data about an Actor:

  • Determine whether actors are local or remote by cheking ther origin IRI
  • Fetch remote actors when data is requestet
    • Send GET request to remote source
    • check the signature

It might be a good idea to add a UI element to force a fetch of remote data, so users can get up-to-date information when needed.

@DanielMowitz commented on GitHub (Jul 26, 2021): In the last few weeks I looked throught the initial comment in this issue and tried to create a plan outlining what the implementation of ForgeFed could look like. The idea was to aid the discussion of the actual code that needs to be written, and not to have a 100% correct roadmap. I hope my proposals are at least somewhat sensible, as I do not have too much experience with either AP/ForgeFed or the Gitea codebase. # Mapping ForgeFed concepts to Gitea By comparing the ForgeFed Actor guidance to Giteas modules, I came to the conclusion that the following mapping should be reasonable: AP | Gitea --- | --- Person | User Project | Project Repository | Repo Group/Organization/Team | Org, Team # Preparing the data model All modules mentioned in the table above should have the following fields added: - Origin IRI - Signing private key - Inbox and Outbox arrays - Possibly followers and following arrays - As far as I could tell, currently each Follow is a seperate object in the Database and the collections are created ad-hoc by iterating over them and checking the user IDs (at least for users) - Array of blocked users - This might be omitted for repos and/or projects since it makes little sense for these actors An instance-wide list of federated/blocked instances needs to be added to the database aswell. The "translation layer" mentioned by @cjslep should be rather straightforward, as the forgefed spec is minimal and gitea has most of the fields already. Some things like "Description" -> "summary" need to be kept in mind though. # Implementing ActivityPub behaviour From this point onward there are two possible routes: ## Implementing it all by hand When not using a library to abstract the ActivityPub functions, this would be my proposed way of adding federated behaviour to Gitea: - Define an actor interface that contains functions for the following tasks: - Accessing the In- and Outbox - Returning the Followers collection - Returning the origin IRI of the actor - Returning the json representation of the actor - Add a new router for serving In- and Outboxes - The Inbox route needs to receive POST requests and create Activity objects to put into the actors inbox - The Outbox route needs to create POST requests from the Activity objects found in the actors outbox and also serve them on receiving a GET request - Create a module that prepares and sends/receives AP activities. It needs to do the following: - Stripping of bcc, deduplication etc. for outbound messages - Checking blocked status and possible forwarding for inbound messages - Sign outgoing and verify the signature of incoming messages (this is optional but a very good idea) - Implement bounded retrying, exponential backoff and ratelimiting - Update the local version of the actors accordingly The following is an example of a repos json representation: ```json { "@context": [ "https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1", "https://forgefed.peers.community/ns" ], "id": "https://dev.example/aviva/treesim", "type": "Repository", "publicKey": { "id": "https://dev.example/aviva/treesim#main-key", "owner": "https://dev.example/aviva/treesim", "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhki....." }, "inbox": "https://dev.example/aviva/treesim/inbox", "outbox": "https://dev.example/aviva/treesim/outbox", "followers": "https://dev.example/aviva/treesim/followers", "team": "https://dev.example/aviva/treesim/team", "name": "Tree Growth 3D Simulation", "summary": "<p>Tree growth 3D simulator for my nature exploration game</p>" } ``` ## Using Go-Fed The equivalent of writing an actor interface would be implementing the db interface from go-fed. The other two points would then be met by implementing the FederatingProtocol for all actor classes (http signing is possible using go-fed/httpsig). # Fetching ActivityStreams In whatever way it is implemented, at this point Gitea would be able to send and receive Activities as they happen, but it would be nice to also see all the Actors and their activities that came before. To do this, Gitea would have to do the following when a user requests Data about an Actor: - Determine whether actors are local or remote by cheking ther origin IRI - Fetch remote actors when data is requestet - Send GET request to remote source - check the signature It might be a good idea to add a UI element to force a fetch of remote data, so users can get up-to-date information when needed.
Author
Owner

@DanielMowitz commented on GitHub (Jul 26, 2021):

As an aside, from what I read, it seems like SharedInbox would help in generating a timeline of all public activities. To me this seems like a desirable feature for a ForgeFed implementation. My knowledge of AP is not deep enough to have a really meaningful opinion on the topic though and I would love to find out more!
@cjslep, this is not really the right place to discuss this, but I would be really interested in what your issue with SharedInbox is, maybe we can find some place to have that discussion.

@DanielMowitz commented on GitHub (Jul 26, 2021): As an aside, from what I read, it seems like SharedInbox would help in generating a timeline of all public activities. To me this seems like a desirable feature for a ForgeFed implementation. My knowledge of AP is not deep enough to have a really meaningful opinion on the topic though and I would love to find out more! @cjslep, this is not really the right place to discuss this, but I would be really interested in what your issue with SharedInbox is, maybe we can find some place to have that discussion.
Author
Owner

@aschrijver commented on GitHub (Jul 27, 2021):

Thanks for your elaboration. It is great to see the growing interest in federating Gitea!

@cjslep, this is not really the right place to discuss this, but I would be really interested in what your issue with SharedInbox is, maybe we can find some place to have that discussion.

The most appropriate location would be the SocialHub community forum, where there's some prior discussion already, like this topic.

@aschrijver commented on GitHub (Jul 27, 2021): Thanks for your elaboration. It is great to see the growing interest in federating Gitea! > @cjslep, this is not really the right place to discuss this, but I would be really interested in what your issue with SharedInbox is, maybe we can find some place to have that discussion. The most appropriate location would be the [SocialHub](https://socialhub.activitypub.rocks) community forum, where there's some prior discussion already, like [this topic](https://socialhub.activitypub.rocks/t/does-an-actor-have-to-have-their-own-inbox-or-is-a-sharedinbox-enough/1091).
Author
Owner

@pilou- commented on GitHub (Aug 16, 2021):

Posted on behalf of Loic


Loic wrote:

It is also a matter of defining the first baby steps that would lead Gitea in the direction of federation. At the moment there only is a very high level discussion that can hardly be translated into actionable items. In your expert opinion, what would be the first minimal tasks that would make most sense?

@zeripath @cjslep here is an idea for the first baby step: creating a keypair for every user that will be used to sign http requests (see also the IETF draft). Although signing http requests is not required by ActivityPub or ActivityStreams, it is mentioned in the ActivityPub wikii. Since mastodon, bookwyrm and other ActivityPub implementations verify and expect a signature, it is de facto required.

If it sounds sensible to you, I think the creation of the corresponding issue as well as its implementation is eligible to be funded by the 5,000€ grant made available by the fedeproxy project a month ago:

  • Write a detailed issue to create a keypair for every user, with technical details that would allow a skilled Go developer with no prior knowledge of the codebase to work on it
  • Propose a pull request to implement the issue, add it to the 1.16 roadmap and get it merged
@pilou- commented on GitHub (Aug 16, 2021): Posted on behalf of [Loic](https://forum.fedeproxy.eu/t/advancing-federation-in-gitea/240/26) --- Loic [wrote](https://github.com/go-gitea/gitea/issues/14186#issuecomment-875779897): > It is also a matter of defining the first baby steps that would lead Gitea in the direction of federation. At the moment there only is [a very high level discussion ](https://github.com/go-gitea/gitea/issues/14186) that can hardly be translated into actionable items. In your expert opinion, what would be the first minimal tasks that would make most sense? @zeripath @cjslep here is an idea for the first baby step: **creating a keypair for every user** that will be used to [sign http requests](https://github.com/go-fed/httpsig) (see also the [IETF draft](https://tools.ietf.org/html/draft-cavage-http-signatures)). Although signing http requests is [not required by ActivityPub](https://www.w3.org/TR/activitypub/#security-verification) or [ActivityStreams](https://www.w3.org/TR/activitystreams-core), it is mentioned in the [ActivityPub wikii](https://www.w3.org/wiki/SocialCG/ActivityPub/Authentication_Authorization#Signing_requests_using_HTTP_Signatures). Since mastodon, bookwyrm and other ActivityPub implementations verify and expect a signature, it is de facto required. If it sounds sensible to you, I think the creation of the corresponding issue as well as its implementation is eligible to be funded by the [5,000€ grant made available by the fedeproxy project a month ago](https://forum.fedeproxy.eu/t/howto-5-000-grant-earmarked-for-gitea-federation/330): * Write a detailed [issue](https://github.com/go-gitea/gitea/issues) to **create a keypair for every user**, with technical details that would allow a skilled Go developer with no prior knowledge of the codebase to work on it * Propose a pull request to implement the issue, add it to the [1.16 roadmap](https://github.com/go-gitea/gitea/issues/16429) and get it merged
Author
Owner

@thebiblelover7 commented on GitHub (Sep 20, 2021):

Any news on this? So exited to have this when it is done!

@thebiblelover7 commented on GitHub (Sep 20, 2021): Any news on this? So exited to have this when it is done!
Author
Owner

@techknowlogick commented on GitHub (Sep 20, 2021):

@thebiblelover7 please see the pinned issue https://github.com/go-gitea/gitea/issues/16827

@techknowlogick commented on GitHub (Sep 20, 2021): @thebiblelover7 please see the pinned issue https://github.com/go-gitea/gitea/issues/16827
Author
Owner

@rosariop commented on GitHub (Sep 13, 2023):

is this still active?
I am interested in build on a fediverse api build in golang and I'd be willing to support implementing it in the first place too!

@rosariop commented on GitHub (Sep 13, 2023): is this still active? I am interested in build on a fediverse api build in golang and I'd be willing to support implementing it in the first place too!
Author
Owner

@ghost commented on GitHub (Sep 14, 2023):

is this still active? I am interested in build on a fediverse api build in golang and I'd be willing to support implementing it in the first place too!

I don't think any of the Gitea developers are actively working on federation, but there's been some progress in implementing it in Forgejo. I've personally been busy with other stuff for the past year or so, but I'm hoping to getting back to working on federation sometime in the next month.

@ghost commented on GitHub (Sep 14, 2023): > is this still active? I am interested in build on a fediverse api build in golang and I'd be willing to support implementing it in the first place too! I don't think any of the Gitea developers are actively working on federation, but there's been some progress in [implementing it in Forgejo](https://codeberg.org/forgejo/forgejo/issues/59). I've personally been busy with other stuff for the past year or so, but I'm hoping to getting back to working on federation sometime in the next month.
Author
Owner

@techknowlogick commented on GitHub (Sep 14, 2023):

@Ta180m I'm still sending PRs following my original plan, but as this is a large undertaking it's being done in small parts over time as large PRs make things difficult to review.

@techknowlogick commented on GitHub (Sep 14, 2023): @Ta180m I'm still sending PRs following my original plan, but as this is a large undertaking it's being done in small parts over time as large PRs make things difficult to review.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/gitea#6602