# ForgeFeed *NOTE: This specification is a W.I.P and should not yet be implemented anywhere.* ForgeFeed is a collection of specifications and recommendations which when implemented can enhance interoperability and content discovery of different [code forges](https://en.wikipedia.org/wiki/Forge_(software)) across the internet. Below we cover the following specifications: Repository URI - URI Identifier for WebFinger Queries WebFinger Query - Metadata Queries via WebFinger RSS Specification - Repository Discovery via RSS ## Repository URI A repository URI identifies a code repository and optionally the host that is resides on. This value is similar to [RFC7565](https://datatracker.ietf.org/doc/html/rfc7565). The slug and hostname part MUST match the URI path specification as defined in [RFC3986-3.3](https://www.rfc-editor.org/rfc/rfc3986#section-3.3) while the hostname, if specified, must match [RFC3986-3.2.2](https://www.rfc-editor.org/rfc/rfc3986#section-3.2.2) repository-uri = prefix slug hostname prefix = "repository:" slug = rfc3986-path hostname = [@ rfc3986-hostname] ### Slug The Slug represents a unique string that identifies a repository at a particular code forge. Repository refers to a VCS managed codebase of some kind, e.g. a Git repository. ### Hostname If the hostname part is missing then the address of the server receiving the query is assumed. For example the following two queries are equivalent: ```text https://example.org/.well-known/webfinger?resource=repository:example/spartacus https://example.org/.well-known/webfinger?resource=repository:example/spartacus@example.org ``` TODO: Make this an actual spec, for now, some Python: ```python from urllib.parse import urlparse, quote_plus def from_string(text): url = urlparse(text) if not url.path: return (None, None) split = url.path.split("@", 1) if len(split) == 2: return (split[0], split[1]) return (split[0], None) def to_string(slug, domain=None): if domain: return quote_plus(f"repository:{slug}@{domain}") else: return quote_plus(f"repository:{slug}") ``` ## WebFinger Query A [WebFinger](https://webfinger.net/spec/) query may be used to identify detailed information about a public repository at a particular forge. Here is an example response about a fictitious repository: `GET https://example.org/.well-known/webfinger?resource=repository:example/spartacus` ```json { "subject": "repository:example/spartacus", "aliases": [ "https://example.org/example/spartacus" ], "links": [ { "rel": "http://webfinger.net/rel/avatar", "href": "https://example.org/stylized-logo.png" }, { "rel": "http://forge-feed.org/rel/description", "titles": { "en-us": "A Text Adventure Written in FORTRAN 77", "es": "Una Aventura de Texto Escrita en FORTRAN 77" } }, { "rel": "http://feed-forge.org/rel/clone", "href": "https://example.org/example/spartacus", "properties": { "http://feed-forge.org/ns/vcs-type": "git" } }, { "rel": "http://forge-feed.org/rel/license", "href": "https://example.com/example/spartacus/tree/LICENSE", "properties": { "spdx-identifier": "GPL-2.0-or-later" } }, { "rel": "http://forge-feed.org/rel/chatroom", "href": "ircs://irc.libera.chat/#spartacus-game" "properties": { "http://feed-forge.org/ns/chatroom": "irc" } }, { "rel": "http://forge-feed.org/rel/label", "properties": { "http://feed-forge.org/ns/label": "fortran" } }, { "rel": "http://forge-feed.org/rel/label", "properties": { "http://feed-forge.org/ns/label": "text-adventure" } } ] } ``` ### Properties #### http://feed-forge.org/ns/vcs-type Identifies VCS types, valid strings are: bzr (GNU Bazaar) bazaar.canonical.com darcs (Darcs) darcs.net fossil (Fossil) fossil-scm.org git (Git) git-scm.com hg (Mercurial) mercurial-scm.org pijul (Pijul) pijul.org svn (Apache Subversion) subversion.apache.org #### http://feed-forge.org/ns/chatroom Hint describing the backing type of chatroom. See [uri-schemes](https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml). matrix irc xmpp #### http://feed-forge.org/ns/spdx-identifier Refers to a valid SPDX identifier, see [license-list](https://spdx.org/licenses/) ### Link Extension Types #### Avatar Forges that allow users to configure a logo can expose this information as an avatar for use in other applications. ```json { "rel": "http://webfinger.net/rel/avatar", "href": "https://example.org/stylized-logo.png" } ``` #### Homepage Link to an HTTP representation of the project codebase ```json { "rel": "http://feed-forge.org/rel/homepage", "href": "https://example.org/example/spartacus" } ``` #### Description A short text representation of the repository. ```json { "rel": "http://example.org/rel/description", "titles": { "en-us": "A Text Adventure Written in FORTRAN 77", "es": "Una Aventura de Texto Escrita en FORTRAN 77" } } ``` #### License A license SPDX identifier and link to the license's full text. ```json { "rel": "http://feed-forge.org/rel/license", "href": "https://example.com/example/spartacus/tree/LICENSE", "properties": { "http://feed-forge.org/ns/spdx-identifier": "GPL-2.0-or-later" } } ``` ### Clone Links Clone links define how one can download a copy of the remote software onto their own server. ```json { "rel": "http://feed-forge.org/rel/clone", "href": "https://example.org/example/spartacus", "properties": { "http://feed-forge.org/ns/vcs-type": "git" } } ``` #### Chat Links Links to chatrooms: IRC, Matrix, XMPP, etc. ```json { "rel": "http://feed-forge.org/rel/chatroom", "href": "ircs://irc.libera.chat/#spartacus-game" "properties": { "http://feed-forge.org/ns/chatroom": "irc" } }, { "rel": "http://feed-forge.org/rel/chatroom", "href": "matrix:r/spartacus-game#example.org", "properties": { "http://feed-forge.org/ns/chatroom": "matrix" } }, { "rel": "http://feed-forge.org/rel/chatroom", "href": "xmpp:example.org/spartacus-game", "properties": { "http://feed-forge.org/ns/chatroom": "xmpp" } } ``` #### Mailing Lists Links to associated mailing lists, forms, etc. ```json { "rel": "http://feed-forge.org/rel/mailing-list", "href": "mailto://list-name@mail.example.org", "properties": { "http://feed-forge.org/ns/mailing-list-subscribe": "mailto://subscribe+list-name@mail.example.org", "http://feed-forge.org/ns/mailing-list-unsubscribe": "mailto://unsubscribe+list-name@mail.example.org" } } ``` #### Free-Form Tags Arbitrary, free-form tags. ```json { "rel": "http://example.org/rel/label", "properties": { "http://feed-forge.org/ns/label": "fortran" } }, { "rel": "http://example.org/rel/label", "properties": { "label": "text-adventure" } } ``` ### Security Repositories which are not publicly available should not be identifiable by making webfinger queries at all. A repository which is private MUST return the same response as a repository which does not exist when making a webfinger request. GET https://example.org/.well-known/webfinger?resource=repository:example/spartacus 200 GET https://example.org/.well-known/webfinger?resource=repository:example/private-repository 404 GET https://example.org/.well-known/webfinger?resource=repository:example/non-existent-repository 404 # RSS Feeds Your forge needs to expose an RSS feed in order for other peers to determine what code repositories exist in your server. Your server should expose repositories ordered by recent updates. The heuristic you use to determine "recently updated" depends on your forge. The simplest way to determine recent activity is likely by your VCS's concept of a "commit". ## Determine if a Host Supports Forge Feed In order to participate in ForgeFeed your forge MUST present an HTML link element such as below at the root domain of your forge. For example, `code.example.org` MUST have a link element present in it's html header: ```html