This draft is generated from branch beh-intro
, commit 880cccd.
1. Introduction
Note: The spec is still under construction. Want to start implementing? Check out the ActivityPub implementation guide, and then the § 3 Server to Server Interactions section here.
Below are the 3 intro texts from the 3 specs. We probably want to replace them with a human-friendly tutorial-like example, like in the ActivityPub spec.
The ForgeFed Vocabulary describes a set of types and properties to be used by platforms that support the ForgeFed protocol. This specification describes only the new vocabulary called ForgeFed. The ForgeFed behavior specification describes how to use this vocabulary, along with standard ActivityPub vocabulary, to support the ForgeFed protocol.
The ForgeFed modeling specification is a set of rules and guidelines which describe version control repository and project management related objects and properties, and specify how to represent them as JSON-LD objects (and linked data in general) using the ForgeFed vocabulary and related vocabularies and ontologies. Using these modeling rules consistently across implementations and instances allows to have a common language spoken across networks of software forges, project management apps and more.
The ForgeFed vocabulary specification defines a dedicated vocabulary of forge-related terms, and the modeling specification uses these terms, along with terms that already exist in ActivityPub or elsewhere and can be reused for forge federation.
The ForgeFed behavior specification provides instructions for using Activities, and which Activities and properties to use, to represent forge events, and describes the side-effects these Activities should have. The objects used as inputs and outputs of behavior descriptions there are defined here in the modeling specification.
The ForgeFed behavior specification is a set of instructions for representing version control systems and project management related transactions using ActivityPub activity objects, and it describes the side effects and expected results of sending and receiving these activities. The vocabulary for these activities includes standard ActivityPub terms, new terms defined by ForgeFed, and terms borrowed from other external vocabularies.
The ForgeFed vocabulary specification defines a dedicated vocabulary of forge-related terms, and the behavior specification uses these terms, along with terms that already exist in ActivityPub or elsewhere and can be reused for forge federation.
The ForgeFed modeling specification defines rules for representing forge related objects as ActivityPub JSON-LD objects, and these objects are used in the behavior specification, included in activities, mentioned in activities, or modified as a result of activity side-effects.
2. Objects
2.1. Kinds of Objects
Objects are the core concept around which both ActivityPub and ForgeFed are built. Examples of Objects are Note, Ticket, Image, Create, Push. Some objects are resources, which are objects that contain or represent information and user made or program made content, and some objects are helpers that exist as implementation detail aren’t necessarily exposed to humans or are useful to humans. But everything is an Object, represented as compacted JSON-LD.
ForgeFed is an ActivityPub extension, and communication between ForgeFed implementations occurs using activity objects sent to actor inboxes and outboxes.
There are 4 kinds of objects in ForgeFed:
- Activities
-
These are objects that describe actions, such as actions that happened, actions that are happening, or a request to perform an action. Their primary use is for server-to-server interaction between actors by being sent to an actor’s inbox, and client-to-server interaction between a person or program and an actor they control by being sent to the actor’s outbox. Activities can also appear or be linked inside other objects and activities and be listed in Collections.
- Actors
-
These are static persistent objects that have an inbox and can be directly interacted with by POSTing activities to it. Their primary use is to contain or represent information and output of user actions or program actions, and to manage access to this information and modifications of it.
- Child objects
-
These are persistent objects that, like actors, contain or represent information and output of user actions or program actions, but they do not have their own inbox and are not directly interacted with. A managed static object always has a parent object, which is an actor, and that actor’s inbox is the way to interact with the child object. The parent actor manages access and modification of the child object.
- Global helper objects
-
These are objects that do not belong to any actor and do not need any interaction through activities. As such, they do not exactly fit into the actor model, but may be involved in implementation details and practical considerations.
Actors, children, and globals are referred to in ForgeFed as static objects, while activities are dynamic objects. The terms constant and variable are used to indicate whether an object changes during its lifetime or not.
Static objects, in addition to being an actor or child or global, also have a resource/helper distinction:
- Resource
-
Contains or represents information and user made or program made content, usually belongs to the domain model of version control systems and project management.
- Helper
-
Used for running things behind the scenes, not exposed directly as user content, may be transient or auto generated, usually related to implementation detail and not to concepts of version control and project management.
2.2. Object Publishing and Hosting
In ForgeFed, actors host their child objects locally, meaning the actor and the child object are hosted on the same instance. Actors may create remote objects by offering them to the relevant actor, which then may create the object on their side and assign it a URI.
The process begins with an Offer activity, in which:
-
object MUST be the object being offered for publishing, and that object MUST NOT have an id
-
target MUST indicate under which list/collection/context the sender would like the object to be published (it may also be the URI of the target actor itself)
Among the recipients listed in the Offer’s recipient fields, exactly one recipient is the actor who is responsible for inspecting and possibly publishing the newly created object, and possibly sending back an Accept or a Reject. We’ll refer to this actor as the target actor. Specific object types described throughout this specification have a specific meaning for the target actor, which processing and inspection it is expected to do, and where it is expected to list the URI of the object once it publishes it.
The sender is essentially asking that the target actor hosts the object as a child object and assigns is a URI, allowing to observe and interact with the object. The target actor will be responsible for hosting and controlling the object, and the sender will just be mentioned as the author.
When an actor A receives the Offer activity, they can determine whether they’re the target actor as follows: If the target is A or a child object of A, then A is the target actor. Otherwise, A isn’t the target actor.
In the following example, Luke wants to open a ticket under Aviva’s Game Of Life simulation app:
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://forge.example/luke/outbox/02Ljp" , "type" : "Offer" , "actor" : "https://forge.example/luke" , "to" : [ "https://dev.example/aviva/game-of-life" , "https://dev.example/aviva/game-of-life/team" , "https://dev.example/aviva/game-of-life/followers" ], "object" : { "type" : "Ticket" , "attributedTo" : "https://forge.example/luke" , "summary" : "Test test test" , "content" : "<p>Just testing</p>" , "mediaType" : "text/html" , "source" : { "mediaType" : "text/markdown; variant=Commonmark" , "content" : "Just testing" } }, "target" : "https://dev.example/aviva/game-of-life" }
The target actor SHOULD send an Accept or a Reject activity to the Offer’s author in response. If the target actor sends an Accept, it MUST host its own copy, assigning an id to the newly published object and adding it to the expected list specified by the Offer’s target.
If the target actor sends a Reject, it MUST NOT add the object’s id to that list. However if the target actor doesn’t make any use of the
object, it MAY choose not to send a Reject, e.g. to protect user privacy. The Accept
or Reject
may also be delayed, e.g. until review by a human user;
that is implementation dependent, and implementations should not rely on an
instant response.
In the Accept activity:
-
result MUST be specified and be the id of the new child object now hosted by the target actor, which is extracted from the Offer’s object
In the following example, Luke’s ticket is opened automatically and Aviva’s Game Of Life repository, which is an actor, automatically sends Luke an Accept activity:
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://dev.example/aviva/game-of-life/outbox/096al" , "type" : "Accept" , "actor" : "https://dev.example/aviva/game-of-life" , "to" : [ "https://forge.example/luke" , "https://dev.example/aviva/game-of-life/team" , "https://dev.example/aviva/game-of-life/followers" ], "object" : "https://forge.example/luke/outbox/02Ljp" , "result" : "https://dev.example/aviva/game-of-life/issues/113" }
3. Server to Server Interactions
This section describes the whole flow of actor interactions, that allows the federated implementation of the various features of forges and related software. It provides a complete picture of interaction flows, which the actor API section can’t, because it focuses on a single actor type at a time.
3.1. Following
Minimal required role: visit
Following can be done using a Follow activity, and unfollowing can be done via an Undo activity whose object is a Follow. And the receiving actor sends back an Accept or Reject (or nothing). See the ActivityPub specification section on S2S Follow for more details.
However, ForgeFed adds certain elements:
-
The Follow’s object is either an actor or an object managed by an actor. For example, it’s possible to follow a specific Ticket, not just the whole TicketTracker. In that case, the TicketTracker receives the Follow, recognizes that the object is one of its tickets, and responds as normal with Accept/Reject.
-
Following requires the visit role, i.e. for the Follow to specify a valid capability. For publicly visible objects (such as public projects on typical FOSS code hosting platforms), the capability MAY be omitted.
3.2. Reporting Pushed Commits
-
Role required for pushing: write
-
Role required for reporting a Push: None (because the Repository itself is publishing the Push)
The ForgeFed Push activity can be used for representing an action of pushing commits into a Repository. Two actors are involved in the process, the pusher (usually a person) and the repository, and they may be hosted on different instances.
Push activities MUST be authored and published by the Repository, not by the actor that pushed. That actor is specified in the Push’s attributedTo property.
Upon a successful push, a ForgeFed implementation that publishes a Push activity MUST provide the type, actor, attributedTo and target properties as described in § 6.8 Push.
See example in § 6.8 Push.
3.3. Issues
3.3.1. Open
Minimal required role: report
The first step for opening a ticket is to determine to which actor to send the ticket. We’ll refer to this actor as the ticket tracker. Given an object obj against which you’d like to open a ticket (e.g. some application’s source code repository), look at the ticketsTrackedBy property of obj.
-
If
ticketsTrackedBy
isn’t specified, then obj does’t declare a way to open tickets via ForgeFed. -
If
ticketsTrackedBy
is specified and is set to the id of obj itself, that means obj manages its own tickets, i.e. it is the ticket tracker to which you’ll send the ticket. -
If
ticketsTrackedBy
is specified and is set to some other object, look at the tracksTicketsFor property of that other object. If the id of obj is listed there undertracksTicketsFor
, then that other object is the ticket tracker to which you’ll send the ticket. Implementations SHOULD verify this bidirectional reference between the object and the tracker, and SHOULD NOT send a ticket if the bidirectional reference isn’t found.
Now that we’ve determined the ticket tracker, i.e. the actor to whom we’ll send the Ticket, the ticket may be opened using an Offer activity in which:
-
object is the ticket to be opened, it’s a Ticket object with fields as described in § 6.9 Ticket. It MUST specify at least attributedTo, summary and content, and MUST NOT specify id. If it specifies a context, then it MUST be identical the Offer’s target described below.
-
target is the ticket tracker to which the actor is offering the Ticket (e.g. a repository or project etc. under which the ticket will be opened if accepted). It MUST be either an actor or a child object. If it’s a child object, the actor to whom the child object belongs MUST be listed as a recipient in the Offer’s to field. If it’s an actor, then that actor MUST be listed in the
to
field.
The target actor MAY then send back an Accept or Reject. The action that has been taken by the target actor is indicated to the ticket author as follows:
-
If a Reject was sent, it means the ticket hasn’t been assigned an id URI by the tracker and isn’t being tracked by the tracker
-
If an Accept was sent, it means the ticket is now tracked and hosted on the target’s side
In the following example, Luke wants to open a ticket under Aviva’s Game Of Life simulation app:
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://forge.example/luke/outbox/02Ljp" , "type" : "Offer" , "actor" : "https://forge.example/luke" , "to" : [ "https://dev.example/aviva/game-of-life" , "https://dev.example/aviva/game-of-life/team" , "https://dev.example/aviva/game-of-life/followers" ], "object" : { "type" : "Ticket" , "attributedTo" : "https://forge.example/luke" , "summary" : "Test test test" , "content" : "<p>Just testing</p>" , "mediaType" : "text/html" , "source" : { "mediaType" : "text/markdown; variant=Commonmark" , "content" : "Just testing" } }, "target" : "https://dev.example/aviva/game-of-life" }
Luke’s ticket is opened automatically and Aviva’s Game Of Life repository, which is an actor, automatically sends Luke an Accept activity:
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://dev.example/aviva/game-of-life/outbox/096al" , "type" : "Accept" , "actor" : "https://dev.example/aviva/game-of-life" , "to" : [ "https://forge.example/luke" , "https://dev.example/aviva/game-of-life/team" , "https://dev.example/aviva/game-of-life/followers" ], "object" : "https://forge.example/luke/outbox/02Ljp" , "result" : "https://dev.example/aviva/game-of-life/issues/113" }
3.3.2. Update title and description
See § 3.13 Editing an Object and § 3.13.2 Edit a Ticket’s title and description.
3.3.3. Close
Minimal required role: triage
Given:
-
A TicketTracker actor, T
-
An actor with triage access to T, Alice
-
A Ticket t, that is tracked by T
If t is open, i.e. its isResolved isn’t specified or is set to False, t may be closed via the following steps:
-
Alice sends T a Resolve activity where:
-
object is the URI of t
-
capability is the URI of a Grant authorizing the action
-
-
T sets t's isResolved to True, and MAY set resolvedBy to Alice or to the Resolve, and MAY set resolved to the current time
3.3.4. Reopen
Minimal required role: triage
Given:
-
A TicketTracker actor, T
-
An actor with triage access to T, Alice
-
A Ticket t, that is tracked by T
If t is closed, i.e. its isResolved is True, t may be reopened via the following steps:
-
Alice sends T a Undo activity whose:
-
capability is the URI of a Grant authorizing the action
-
T sets t's isResolved to False
3.4. Merge Requests
3.4.1. Open
Minimal required role: report
If actor A wishes to submit a Merge Request (MR)/Pull Request (PR)/patch against a Repository R, it may do so by following these steps:
-
Look at R's sendPatchesTo property: That is the PatchTracker to which the MR needs to be submitted; let’s call it P
-
Verify that P consents to handling MRs for repository R by verifying that R is listed in P's tracksPatchesFor property
-
Publish and deliver, at least to P, an Offer activity in which:
-
actor is A
-
target is P
-
-
id isn’t specified
-
attributedTo is A
-
summary is a one-line HTML-escaped plain-text title of the MR
-
source is the MR’s description
-
content is an HTML rendering of the MR’s description
-
context, if specified, is P
-
Among the attachments there’s exactly one of type Offer, in which:
-
origin is the Repository or Branch from which the proposed changes are proposed to be merged into the target repository/branch
-
target is the Repository or Branch into which the changes are proposed to be merged
-
object is an OrderedCollection of Patch objects in reverse chronological order, all of them with:
-
the same mediaType
-
that mediaType MUST match the Version Control System of the target Repository
-
attributedTo MUST be A
-
-
At least origin or object MUST be provided, both MAY be provided
-
-
Actor P MAY send back an Accept or Reject. The action that has been taken by P is indicated to actor A as follows:
-
If a Reject was sent, it mean the MR has been rejected, and isn’t being tracked by P
-
If an Accept was sent, it means the MR is now tracked by P, and its id is indicated by the Accept’s result
In the following example, Luke wants to open a Merge Request against a Game Of Life simulation app:
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://forge.example/luke/outbox/uCSW6urN" , "type" : "Offer" , "actor" : "https://forge.example/luke" , "to" : [ "https://dev.example/projects/game-of-life/pr-tracker" ], "cc" : [ "https://dev.example/projects/game-of-life" , "https://dev.example/projects/game-of-life/followers" , "https://dev.example/projects/game-of-life/repo" , "https://dev.example/projects/game-of-life/repo/followers" , "https://dev.example/projects/game-of-life/pr-tracker/followers" ], "object" : { "type" : "Ticket" , "attributedTo" : "https://forge.example/luke" , "summary" : "Fix the animation bug" , "content" : "<p>Please review, thanks!</p>" , "mediaType" : "text/html" , "source" : { "mediaType" : "text/markdown; variant=Commonmark" , "content" : "Please review, thanks!" }, "attachment" : { "type" : "Offer" , "origin" : { "type" : "Branch" , "context" : "https://forge.example/luke/game-of-life" , "ref" : "refs/heads/fix-animation-bug" }, "target" : { "type" : "Branch" , "context" : "https://dev.example/projects/game-of-life/repo" , "ref" : "refs/heads/main" }, "object" : { "type" : "OrderedCollection" , "totalItems" : 1 , "items" : [ { "type" : "Patch" , "attributedTo" : "https://forge.example/luke" , "mediaType" : "application/x-git-patch" , "content" : "From c9ae5f4ff4a330b6e1196ceb7db1665bd4c1..." } ] } } }, "target" : "https://dev.example/projects/game-of-life/pr-tracker" }
Luke’s MR is opened automatically and the PatchTracker sends Luke an Accept activity:
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://dev.example/projects/game-of-life/pr-tracker/outbox/qQfFKwJ8" , "type" : "Accept" , "actor" : "https://dev.example/projects/game-of-life/pr-tracker" , "to" : [ "https://forge.example/luke" ], "cc" : [ "https://dev.example/projects/game-of-life" , "https://dev.example/projects/game-of-life/followers" , "https://dev.example/projects/game-of-life/repo" , "https://dev.example/projects/game-of-life/repo/followers" , "https://dev.example/projects/game-of-life/pr-tracker/followers" ], "object" : "https://forge.example/luke/outbox/uCSW6urN" , "result" : "https://dev.example/projects/game-of-life/pr-tracker/pulls/1219" }
3.4.2. Apply
Minimal required role: write
Given:
-
A Repository actor, R
-
A PatchTracker actor, P, that is tracking patches for R
-
An actor with write access to P, Alice
-
A Ticket t, that is a Merge Request tracked by P
t may be merged into repository R via the following steps:
-
Alice sends P an Apply activity where:
-
object is the URI of t
-
target is the URI of R or a Branch object with context being the URI of R, name being the branch name (e.g. "main") and ref being the unique identifier of the branch within the repo e.g. "refs/heads/main")
-
capability is the URI of a Grant activity granting Alice write access to P
-
-
P verifies that:
-
The Apply’s target matches the target repo/branch specified by t
-
t can be merged without conflict
-
The specified capability is valid
-
-
P, via the version control system’s protocol, pushes the patches/commits to R
-
P publishes an Accept activity whose object points to the Apply, and marks t as resolved
-
R, upon processing the push, publishes a Push activity, see § 3.2 Reporting Pushed Commits.
3.4.3. Update title and description
See § 3.13 Editing an Object and § 3.13.2 Edit a Ticket’s title and description.
3.4.4. Update patches (via web)
Minimal required role:
Given:
-
A Repository actor, R
-
A PatchTracker actor, P, that is tracking patches for R
-
An actor with write access to P, Alice
-
A Ticket t, that is a Merge Request tracked by P
-
t's attachment is an Offer whose object is specified and is an OrderedCollection, in reverse chronological/logical order, of one or more Patch objects
t may receive an updated version of its patch set via the following steps:
-
Alice sends P an Add activity, where:
-
object is an OrderedCollection, in reverse chronological/logical order, or one or more Patch objects, whose mediaType matches the VCS of R (e.g. Git patches for a Git repo)
-
target is the URI of t
-
capability is the URI of a Grant that authorizes this action
-
-
P updates the OrderedCollection of Patch objects under t:
-
The current collection is placed at the top of the previousVersions list
-
The new collection takes the place of the current one, and receives an id field, i.e. a URI
-
The currentVersion fields in all previousVersions items are updated to specify that newly assigned id
-
-
P publishes an Accept where:
For example, here’s what t might look like:
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://fig.fr33domlover.site/looms/9nOkn/cloths/mbWob" , "type" : "Ticket" , "context" : "https://fig.fr33domlover.site/looms/9nOkn" , "attributedTo" : "https://walnut.fr33domlover.site/people/gK2eJ" , "isResolved" : false , "published" : "2022-09-28T16:03:54.327751Z" , "summary" : "Fix the bug" , "source" : { "content" : "One line of code was enough!" , "mediaType" : "text/markdown; variant=Commonmark" }, "mediaType" : "text/html" , "content" : "<p>One line of code was enough!</p>" , "attachment" : { "type" : "Offer" , "object" : "https://fig.fr33domlover.site/looms/9nOkn/cloths/mbWob/bundles/mbWob" , "origin" : { "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "context" : "https://grape.fr33domlover.site/repos/9GnzG" , "name" : "main" , "ref" : "refs/heads/main" , "type" : "Branch" }, "target" : { "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "context" : "https://fig.fr33domlover.site/repos/9nOkn" , "name" : "main" , "ref" : "refs/heads/main" , "type" : "Branch" } }, "followers" : "https://fig.fr33domlover.site/looms/9nOkn/cloths/mbWob/followers" , "replies" : "https://fig.fr33domlover.site/looms/9nOkn/cloths/mbWob/discussion" }
And the collection object pointed by attachment’s object is:
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://fig.fr33domlover.site/looms/9nOkn/cloths/mbWob/bundles/mbWob" , "type" : "OrderedCollection" , "context" : "https://fig.fr33domlover.site/looms/9nOkn/cloths/mbWob" , "orderedItems" : [ "https://fig.fr33domlover.site/looms/9nOkn/cloths/mbWob/bundles/mbWob/patches/4nZwD" ], "previousVersions" : [ "https://fig.fr33domlover.site/looms/9nOkn/cloths/mbWob/bundles/J7f4T" , "https://fig.fr33domlover.site/looms/9nOkn/cloths/mbWob/bundles/m6F29" ], "totalItems" : 1 }
Note that context points back to t and the item under orderedItems points to a Patch object, i.e. it’s a MR with a single patch. And there are already 2 older versions.
After processing the Add, t now looks like this - the only change here is in line 23 which points to the new collection now:
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://fig.fr33domlover.site/looms/9nOkn/cloths/mbWob" , "type" : "Ticket" , "context" : "https://fig.fr33domlover.site/looms/9nOkn" , "attributedTo" : "https://walnut.fr33domlover.site/people/gK2eJ" , "isResolved" : false , "published" : "2022-09-28T16:03:54.327751Z" , "summary" : "Fix the bug" , "source" : { "content" : "One line of code was enough!" , "mediaType" : "text/markdown; variant=Commonmark" }, "mediaType" : "text/html" , "content" : "<p>One line of code was enough!</p>" , "attachment" : { "type" : "Offer" , "object" : "https://fig.fr33domlover.site/looms/9nOkn/cloths/mbWob/bundles/5Km3d" , "origin" : { "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "context" : "https://grape.fr33domlover.site/repos/9GnzG" , "name" : "main" , "ref" : "refs/heads/main" , "type" : "Branch" }, "target" : { "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "context" : "https://fig.fr33domlover.site/repos/9nOkn" , "name" : "main" , "ref" : "refs/heads/main" , "type" : "Branch" } }, "followers" : "https://fig.fr33domlover.site/looms/9nOkn/cloths/mbWob/followers" , "replies" : "https://fig.fr33domlover.site/looms/9nOkn/cloths/mbWob/discussion" }
That new collection looks like this:
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://fig.fr33domlover.site/looms/9nOkn/cloths/mbWob/bundles/5Km3d" , "type" : "OrderedCollection" , "context" : "https://fig.fr33domlover.site/looms/9nOkn/cloths/mbWob" , "orderedItems" : [ "https://fig.fr33domlover.site/looms/9nOkn/cloths/mbWob/bundles/mbWob/patches/6F94J" , "https://fig.fr33domlover.site/looms/9nOkn/cloths/mbWob/bundles/mbWob/patches/0P5bE" , "https://fig.fr33domlover.site/looms/9nOkn/cloths/mbWob/bundles/mbWob/patches/hDJ8r" , "https://fig.fr33domlover.site/looms/9nOkn/cloths/mbWob/bundles/mbWob/patches/I8Y6c" ], "previousVersions" : [ "https://fig.fr33domlover.site/looms/9nOkn/cloths/mbWob/bundles/mbWob" , "https://fig.fr33domlover.site/looms/9nOkn/cloths/mbWob/bundles/J7f4T" , "https://fig.fr33domlover.site/looms/9nOkn/cloths/mbWob/bundles/m6F29" ], "totalItems" : 4 }
Note that the new version happens to have 4 patches/commits, and that previousVersions now also lists the last version, that we just replaced.
And here’s the collection we replaced, which now has currentVersion pointing to the new collection (and it doesn’t specify previousVersions anymore, since that information can be found under the latest collection).
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://fig.fr33domlover.site/looms/9nOkn/cloths/mbWob/bundles/mbWob" , "type" : "OrderedCollection" , "context" : "https://fig.fr33domlover.site/looms/9nOkn/cloths/mbWob" , "orderedItems" : [ "https://fig.fr33domlover.site/looms/9nOkn/cloths/mbWob/bundles/mbWob/patches/4nZwD" ], "totalItems" : 1 , "currentVersion" : "https://fig.fr33domlover.site/looms/9nOkn/cloths/mbWob/bundles/5Km3d" }
3.4.5. Update patches (via push)
Minimal required role:
-
For the repo push access: write
Given:
-
A Repository actor, R
-
A PatchTracker actor, P, that is tracking patches for R
-
An actor with write access to R, Luke
-
A Ticket t, that is a Merge Request tracked by P
-
t's attachment is an Offer whose origin is specified and is a URI or a Repository, or a Branch object (depending on whether the VCS supports branches, e.g. Git does but Darcs doesn’t)
t may receive an updated version of its patch set, by having Luke perform a VCS push to the origin repository/branch. It may be done via the following steps:
-
Luke pushes (or force-pushes, i.e. adding, changing or deleting commits) to the origin repository/branch
-
P, which SHOULD be a follower of the origin repository, receives the Push activity and checks if any of its Merge Requests have that repository/branch as their origin - indeed t is such a Merge Request
-
P pulls the origin repo/branch, compares it to the Offer’s target repo/branch, and updates the Offer’s object, i.e. the patch collection, in the same manner as described in § 3.4.4 Update patches (via web). Note that if no object collection is specified, P isn’t required to generate patches. However, if it’s specified, P MUST either update it or remove it.
3.4.6. Close
A Merge Request may be closed without being merged/applied. It is the same process as for issues, see § 3.3.3 Close.
3.4.7. Reopen
A Merge Request that was closed without being merged/applied can be reopened. Aside from that constraint, it is the same process as for issues. See § 3.3.4 Reopen.
3.5. Commenting
Minimal required role: report
A comment on a ForgeFed resource object (such as tickets, merge requests) MUST be published as a Create activity, in which object is a Note with fields as described in § 6.1 Comment.
In the following example, Luke replies to Aviva’s comment under a merge request he submitted earlier against her Game Of Life simulation app repository:
{ "@context" : "https://www.w3.org/ns/activitystreams" , "id" : "https://forge.example/luke/outbox/rLaYo" , "type" : "Create" , "actor" : "https://forge.example/luke" , "to" : [ "https://forge.example/luke/followers" , "https://dev.example/aviva/game-of-life" , "https://dev.example/aviva/game-of-life/followers" , "https://dev.example/aviva/game-of-life/team" , "https://dev.example/aviva/game-of-life/merge-requests/19/followers" , "https://dev.example/aviva/game-of-life/merge-requests/19/team" ], "object" : { "id" : "https://forge.example/luke/comments/rD05r" , "type" : "Note" , "attributedTo" : "https://forge.example/luke" , "to" : [ "https://forge.example/luke/followers" , "https://dev.example/aviva/game-of-life" , "https://dev.example/aviva/game-of-life/followers" , "https://dev.example/aviva/game-of-life/team" , "https://dev.example/aviva/game-of-life/merge-requests/19/followers" , "https://dev.example/aviva/game-of-life/merge-requests/19/team" ], "context" : "https://dev.example/aviva/game-of-life/merge-requests/19" , "inReplyTo" : "https://dev.example/aviva/comments/E9AGE" , "mediaType" : "text/html" , "content" : "<p>Thank you for the review! I'll submit a correction ASAP</p>" , "source" : { "mediaType" : "text/markdown; variant=Commonmark" , "content" : "Thank you for the review! I'll submit a correction ASAP" }, "published" : "2019-11-06T20:49:05.604488Z" } }
3.6. Granting access to shared resources
Minimal required role: admin
An actor that wishes to give other specific actors access to view or modify it (or a child object of it), SHOULD do so according to the following instructions.
3.6.1. Object capabilities
3.6.1.1. Introduction
An Object Capability (or in short OCap or OCAP) is a token providing access to certain operations on a certain resource. An actor wishing to act on a resource provides the token to the resource, alongside the Activity they wish to perform. The resource verifies the token, and if and only if it finds the token valid, and access to the requested Activity is allowed by the token, then the resource allows the Activity to be performed.
The token provided by the actor to the resource, i.e. the OCAP, is the ID URI of a previously published Grant activity.
The fundamental steps for accessing shared resources using OCAPs are:
-
The actor managing the resource (which may be the resource itself) sends a
Grant
activity to the actor to whom it wishes to grant access -
When the actor who received the access wishes to operate on the resource, it sends the activity to the actor managing the resource, along with the ID URI of the
Grant
sent in step 1 -
The actor managing the resource verifies the access provided by the
Grant
whose ID URI is provided, and allows the activity to be performed only if the verification passes
Providing the Grant
ID URI like that when requesting to interact with a
resource is called an invocation of the Grant
. There is another operation
possible with a Grant
though: An actor can delegate a Grant
it has
received, i.e. pass on the access, giving it to more actors. Delegation is
covered in a later section; for now let’s assume Grant
s
are used only for invocation. We therefore get the following simplified
validation process.
When an actor R receives from actor A a request to access/modify a resource r, where the request is expressed as an activity a whose capability field specifies some other activity g, then R can validate a (i.e. decide whether or not to perform the requested action) using the following steps:
-
Resource r MUST be a resource that R manages (it may be R itself)
-
g's context MUST be r
-
g's target MUST be A
-
Verify that g doesn’t specify delegates
-
g's actor MUST be R
-
Verify that R indeed published g and considers it an active grant (i.e. R hasn’t disabled/revoked it)
-
checkLeaf(g):
-
Verify that the action being requested by activity a to perform on resource r is within what R permits for the Role specified by g's object
At this point, activity a is considered authorized, and the requested action may be performed.
3.6.1.2. Direct Granting
When an actor R, managing some resource r, wishes to allow some other actor A to interact with r, under the conditions and permissions specified by Role p, then actor R can send to actor A a Grant activity with the following properties:
-
actor: Specifies actor R
-
context: Specifies resource r
-
target: Specifies actor A
-
object: Specifies role p
-
startTime: (optional) The time at which the Grant becomes valid
-
endTime: (recommended) The time at which the Grant expires
-
delegates: Not used
3.6.1.3. Public and Collective Granting
An object typically has certain operations that it allows any actor to perform, and certain operations that only explicitly authorized actors have access to. For example, on a typical public hosting platform for FOSS projects, opening an issue or PR doesn’t require special permissions. But pushing commits or merging a PR does.
In a Grant activity this can be done using the target field. Instead of pointing to a specific actor, it can alternatively have a special value referring to a certain audience of actors. The supported special values are:
-
Public: Refers to all actors on the network, i.e. this Grant can be used by any actor to manipulate the resource. We’ll refer to such a Grant as a public-Grant.
Using the publicCapability property, an object can specify a public-Grant to be available to anyone wishing to interact with the object.
3.6.1.4. Granting the delegate role
A special case of direct granting is granting permission to delegate: If role p is delegate, then the Grant
actor is allowing the target to delegate Grant
s to the actor, i.e. to send Grant
s meant
for delegation or Grants
that are themselves delegations of other Grant
s
(either start a chain, or extend a chain that some other actor started). More
on delegation in the next sections.
When an actor A wishes to allow some other actor R to delegate Grant
s to
actor A, then actor A can send to actor R a Grant activity
with the following properties:
-
actor: Specifies actor A
-
context: Specifies actor A
-
target: Specifies actor R
-
startTime: (optional) The time at which the Grant becomes valid
-
endTime: (recommended) The time at which the Grant expires
-
delegates: Not used
3.6.1.5. Starting a delegation chain
When an actor R, managing some resource r, wishes to allow or request some other actor A to delegate some access-to-r-under-role-p to certain (or any) other actors that A knows, then actor R can send to actor A a Grant activity with the following properties:
-
actor: Specifies actor R
-
context: Specifies resource r
-
target: Specifies actor A
-
object: Specifies role p
-
startTime: (optional) The time at which the Grant becomes valid
-
endTime: (recommended) The time at which the Grant expires
-
allows: Specifies the conditions under which actor A may delegate this
Grant
(i.e. conditions under which actor R will consider the delegation valid when verifying the chain), and what the recipients of the delegtaions that A will send (which are themselvesGrant
activites) are allowed to do with theseGrants
(invoke? further delegate to certain other actors?) -
delegates: Not used
-
capability: (optional) Specifies a delegate Grant previously given by A to R
The following cases are supported in ForgeFed for starting a delegation chain. The term 'component' used below refers to a forge related service actor. This may be a service of a type defined in ForgeFed (such as Repository, TicketTracker, PatchTracker), or a service defined in some extension.
-
actor is a component, target is a Project
-
Scenario: A component delegates access-to-a-resource-it-manages (which is often simply itself) to a project to which the component belongs
-
allows value to use: gatherAndConvey
-
Conditions for the target project:
-
It SHOULD delegate the
Grant
, allowing onlygatherAndConvey
, to its own parent projects -
It SHOULD delegate the
Grant
, allowing onlydistribute
, to teams to which it allows to access it -
It SHOULD delegate the
Grant
, allowing onlyinvoke
, to people and bots to which it allows to access it -
It SHOULD NOT make any other delegation of this
Grant
, and SHOULD NOT invoke it
-
-
-
actor is a Project, target is a parent Project of it
-
Scenario: A project delegates access-to-a-resource-itself to its parent project
-
allows value to use: Same as 1
-
Conditions for the target project: Same as 1
-
-
actor is a component, target is a Team
-
Scenario: A component delegates access-to-a-resource-it-manages to a team that has been approved to access the component
-
allows value to use: distribute
-
Conditions for the target team:
-
It SHOULD delegate the
Grant
, allowingdistribute
only, to its subteams -
It SHOULD delegate the
Grant
, allowinginvoke
only, to its members -
It SHOULD NOT make any other delegation of this
Grant
, and SHOULD NOT invoke it
-
-
-
actor is a Project, target is a Team
-
Scenario: A project delegates access-to-itself to a team that has been approved to access the project
-
allows value to use: Same as 3
-
Conditions for the target project: Same as 3
-
3.6.1.6. Extending a delegation chain
When an actor A receives a Grant activity g where the target is A, and wishes to pass on the granted access to some other actor B (who isn’t the actor of that Grant
), then actor A can do so by
sending to actor B a new Grant
activity h in which:
-
actor is actor A
-
target is actor B
-
object (i.e. the granted role) is either g's object or a lower-access role than g's object, i.e. provides a subset of the permissions that g's object provides (the latter case is called attenuation)
-
startTime: (optional) The time at which this Grant becomes valid
-
endTime: (recommended) The time at which this Grant expires
-
allows: Specifies the conditions under which actor B may delegate this
Grant
(i.e. conditions under which the delegation will be considered valid when verifying the chain), and what the recipients of the delegtaions that B will send (which are themselvesGrant
activites) are allowed to do with theseGrants
(invoke? further delegate to certain other actors?) -
delegates is activity g
-
capability: (optional) Specifies a delegate Grant previously given by B to A
-
result: a URI that will be used later to verify that h is still active and hasn’t been revoked. Alternatively, an object with id and duration as described below.
The result URI MUST be provided whenever extending a delegation chain. It MUST be a URI that actor A controls, i.e. decides what will be returned by HTTP requests to that URI. Requirements:
-
From the moment that actor A publishes activity h, as long as actor A considers h an active
Grant
and hasn’t revoked it, any HTTP HEAD or HTTP GET request the result URI MUST return an HTTP response status 204 or 200. -
If later activity h is revoked, or actor A is deleted, then from the moment that actor A considers h deactivated, any HTTP HEAD or HTTP GET request to the result URI MUST NOT return an HTTP response status in the 200-299 range. The response status SHOULD be 410 or 404.
result MAY instead specify a JSON object in which:
-
id is the URI as described above
-
(optional) duration specifies a duration that allows the recovation URI check to be skipped, if the duration hasn’t yet passed since the last check of the URI. If duration is specified, it MUST be positive and include only an integral number of seconds that is less than
2^63
, and no other component. In other words, its format is: The string "PT", then the integer, then the string "S".
In the following cases, g is a request for actor A to extend the
delegation chain, and actor A SHOULD extend the chain by sending Grant
activities, as described for each case.
The term 'component' used below refers to a forge related service actor. This may be a service of a type defined in ForgeFed (such as Repository, TicketTracker, PatchTracker), or a service defined in some extension.
-
Actor A is a Project, AND g's actor is either a component of A or a subproject of A, AND g's allows is a single value gatherAndConvey
-
Scenario: Project A received some access from a component/subproject of it, and is requested to pass it on its member people, to its member teams, and to its parent projects
-
Requirements for extending the delegation chain:
-
For each parent project P of project A, project A SHOULD publish and deliver to P a
Grant
activity in which:-
actor is project A
-
target is project P
-
object (i.e. the granted role) is either g's object or a lower-access role than g's object
-
allows is a single value gatherAndConvey
-
delegates is activity g
-
capability: (optional) Specifies a delegate Grant previously given by P to A
-
result: a URI that will be used later to verify that h is still active and hasn’t been revoked, or a JSON object as describes above
-
-
For each team T that project A considers a member team with role p, project A SHOULD publish and deliver to T a
Grant
activity in which:-
actor is project A
-
target is team T
-
object (i.e. the granted role) is the lower-access role among g's object and p
-
allows is a single value distribute
-
delegates is activity g
-
capability: (optional) Specifies a delegate Grant previously given by T to A
-
result: a URI that will be used later to verify that h is still active and hasn’t been revoked, or a JSON object as describes above
-
-
For each Person or automated service bot M (that isn’t a team) that project A considers a member with role p, project A SHOULD publish and deliver to M a
Grant
activity in which:-
actor is project A
-
target is actor M
-
object (i.e. the granted role) is the lower-access role among g's object and p
-
delegates is activity g
-
capability: (optional) Specifies a delegate Grant previously given by M to A
-
result: a URI that will be used later to verify that h is still active and hasn’t been revoked, or a JSON object as describes above
-
-
Project A MUST NOT make any other delegations of g, and SHOULD NOT try to invoke it
-
-
-
Actor A is a Team, AND g's actor is either a component/Project in which A is a member or a parent team (see subteams) of A, AND g's allows is a single value distribute
-
Scenario: Team A received some access from a component/project that considers A a member team, or from a parent team of A, and A is requested to pass it on its member people and to its subteams
-
Requirements for extending the delegation chain:
-
For each team T that team A considers a subteam, team A SHOULD publish and deliver to T a
Grant
activity in which:-
actor is team A
-
target is team T
-
allows is a single value distribute
-
delegates is activity g
-
capability: (optional) Specifies a delegate Grant previously given by T to A
-
-
For each Person or automated service bot M (that isn’t a team) that team A considers a member with role p, team A SHOULD publish and deliver to M a
Grant
activity in which: -
Team A MUST NOT make any other delegations of g, and SHOULD NOT try to invoke it
-
-
3.6.1.7. Revoking a Grant
At any point after an actor A publishes a § 7.1.3 Grant in which it
grants some actor B access to a resource that actor A manages, actor A MAY cancel that Grant
, deciding it’s no longer a valid OCAP to use via the capability property of activies that actor B sends.
If actor A cancels such a Grant
, it SHOULD publish and deliver, at least to
actor B, a Revoke activity notifying about the canceled Grant
. In the Revoke
activity, actor A MUST specify the Grants being
revoked, via the object property, where each Grant is specified in one of
the following ways:
-
The Grant is specified by its
id
URI -
The whole Grant activity object is provided, and MUST contain an integrity proof
Additional requirements:
-
Implementations displaying a
Revoke
activity or an interpretation of it in a human interface MUST examine theRevoke
’s object property if it is present, check if any of theGrant
s listed are delegations, and communicate that detail in the human interface
Once actor A publishes the Revoke
, it MUST from now on refuse to execute
requests from actor B to access resources that actor A manages, coming as
activities that specify any of the canceled Grant
s in the capability
property. If actor A receives such an activity from actor B, it SHOULD
publish and send back a Reject activity, whose object specifies the
activity that actor B sent.
If the Grant
that actor A is revoking specifies a result, then from now
on any HTTP HEAD request to the URI specified by result MUST NOT return an
HTTP response status in the 200-299 range. The returned status SHOULD be 410
or 404. See Extending a delegation chain for
more information.
3.6.1.8. Verifying an invocation
A previous section described direct usage of Grants, where the resource actor gives some access to a target actor, and the target actor then uses it to interact with the resource. Another way to give authorization is via delegation chains:
-
The resource actor passes access to a target actor, allowing (or requesting) the target actor to pass this access (or reduced access) on to more actors
-
If authorized by the delegation, those actors may further pass on the access (possibly reduced)
-
Eventually, an actor that received such a delegation may use it to access the resource
Access is delegated using Grant activities as well, using the delegates property to point from each Grant
in the chain to
the previous one. The "direct" Grant
discussed earlier is simply a delegation
chain of length 1.
When an actor R receives from actor A a request to access/modify a resource r, where the request is expressed as an activity a whose capability field specifies some other activity g, then R can validate a (i.e. decide whether or not to perform the requested action) using the following steps.
R begins by verifying that resource r is indeed a resource that R manages (it may be R itself). Otherwise, verification has failed.
R proceeds by collecting the delegation chain in a list, by traversing the chain backwards from the leaf all the way to the beginning of the chain. The traversal starts with the list L being empty, and R examines activity g:
-
g's context MUST be r
-
g's target MUST be A
-
g MUST NOT already be listed in L
-
Look at g's delegates:
-
If g doesn’t specify delegates:
-
g's actor MUST be R
-
Verify that R indeed published g and considers it an active grant (i.e. R hasn’t disabled/revoked it)
-
Prepend g to the beginning of L, resulting with new list M
-
We’re done with the traversal step, the output is M
-
-
If g's delegates is some activity h:
-
g's actor MUST NOT be R
-
g MUST specify exactly one result URI
-
Verify the result:
-
If it’s an object with duration specified, and this duration of time hasn’t yet passed since the last check, proceed without checking the URI
-
Otherwise, send an HTTP HEAD request to the URI, The HTTP response status MUST be 200 or 204
-
-
Prepend g to the beginning of L, resulting with new list M
-
Continue traversal by going back to step 1, but with M being the list, and with g's actor instead of A, and now examining activity h
-
-
"Going back to step 1" refers to the top-level list item; should probably tweak the CSS to display nested lists differently.
R proceeds by traversing the resulting list L from the beginning forward, all the way to the leaf, validating and tracking attenuation in each step. R starts this by examining the first item in L, let’s call this item g:
-
Let p be g's object
-
Examine g's position in L:
-
If g is the last item in L:
-
Perform checkLeaf on g (see below)
-
Verify that the action being requested by activity a to perform on resource r is within what R permits for Role p.
-
We’re done with the traversal!
-
-
Otherwise:
-
Let h be the next item after g in L
-
Let q be h's object
-
The permissions that role q allows on resource r MUST be identical to or a subset of the permissios that role p allows on r
-
Perform checkItem on (g, h) (see below)
-
Continue traversal by going back to step 2, but with h instead of g and q instead of p
-
-
"Step 2" refers to the top-level one, need to tweak CSS for lists
The steps checkLeaf and checkItem mentioned above MAY be extended by implementations, by using custom values in the allows property. But here are the standard definitions, using the values defined in ForgeFed:
checkLeaf (g):
-
g's target (which is actor A, the sender of activity a) SHOULD be an actor of a type to which R allows to perform activity a on resource r, i.e. A should probably be a Person, or some automated service/bot
checkItem (g, h):
-
g MUST specify exactly one value for allows
-
That value MUST be either gatherAndConvey or distribute
-
If it’s gatherAndConvey:
-
If it’s distribute:
-
h's allows MUST be either distribute or invoke
-
At this point, activity a is considered authorized, and the requested action may be performed.
3.6.1.9. Identifying resources and their managing actors
Some shared resources are themselves actors. Some shared resources aren’t actors, but they are child objects of actors. When some actor A wishes to access a resource R and perform a certain operation, it needs to determine which actor to contact in order to request that operation. Actor A then looks at resource R, and the following MUST hold:
-
Either the resource R isn’t an actor (i.e. doesn’t have an inbox) but does specify which actor manages it via the managedBy property;
-
Or the resource R is an actor, i.e. it has an inbox (it doesn’t have to specify managedBy, but if it does, then it MUST refer to itself)
Therefore any object that wishes to be specified as the context of a Grant MUST either be an actor or be managedBy an actor.
3.6.1.10. Invoking a Grant
Invoking a Grant means using the Grant
to authorize a request to
access or modify some resource. If some actor A wishes to access or modify a
resource r, using a Grant
activity g for authorization, preconditions
for a successful invocation include:
-
g's target is actor A (or an audience that includes A, see § 3.6.1.3 Public and Collective Granting)
-
g's context is either the resource r, or a resource in which r is contained, or the actor that manages r
-
g's object is a Role that permits the kind of operation that actor A is requesting to do on resource r
When actor A sends the activity a that requests to access or modify resource r, it can use g for authorization by specifying its id URI in the capability property of activity a.
To have a chance to access resource r, actor A needs to deliver activity a to the actor that manages r. See above instructions for determining who that actor is.
3.6.1.11. Time Bounds
A Grant activity MUST be considered valid for invocation (or as a valid link in a delegation chain) if and only if the current time, at the time of invocation, is within the time bounds defined by the Grant:
-
A Grant MAY specify a startTime: The time at which the Grant becomes valid. If specified, the Grant is valid only if the time of invocation is equal or greater than the startTime
-
A Grant SHOULD specify an endTime: The time at which the Grant expires. If specified, the Grant is valid only if the time of invocation is less than the endTime
Suggested default for picking the endTime: 6 months after publishing the Grant.
3.6.2. Granting access
3.6.2.1. Initial Grant upon resource creation
When an actor A requests to create a new shared resource R, and the resource actor approves and creates it, then the resource actor SHOULD send
a Grant
to actor A, which provides actor A with access to resource R.
The Role specified by the Grant’s object MUST be admin, which means full access to R, including the ability to gives access-to-R to more actors (using an Invite activity, see below).
If such a Grant
is sent by the resource actor upon the creation of resource R, then the Grant
’s fulfills property MUST be provided and
specify the ID URI of the activity (published by actor A) that requested to
create resource R (typically this would be a Create activity, see Object Publishing and Hosting).
If R is a Project or a Team, additional steps occur:
-
A, seeing R's Grant, publishes a delegate-Grant in which the target is R and capability is R's Grant
-
From now on, whenever R wishes to extend a Grant chain to A, it uses A's delegate-Grant as the capability
3.6.2.2. Offering access using Invite activities
When an actor A wishes to offer actor B access to resource R (where the resource actor who manages R is neither A nor B), then actor A SHOULD use an Invite activity, and the following steps:
-
Actor A publishes and delivers an Invite, at least to actor B and to the resource actor of R, with a relevant capability (see § 7.1.1 Invite for details on the properties to use)
-
If actor B wishes to have the offered access, it publishes and delivers (at least to the resource actor of R) an Accept activity whose object specifies the
Invite
sent by actor A -
The resource actor of R receives the
Invite
and theAccept
and:-
Verifies the
Invite
is authorized, as described above in Verifying an invocation -
Verifies that the
Accept
’s object specifies theInvite
and theAccept
’s actor is theInvite
’s object -
Publishes and delivers a Grant activity (see § 7.1.3 Grant for more details on the properties) where:
-
-
B is now considered a collaborator in R!
-
If R is a Project or a Team, additional steps occur:
-
B, seeing R's Grant, publishes a delegate-Grant in which the target is R and capability is R's Grant
-
From now on, whenever R wishes to extend a Grant chain to B, it uses B's delegate-Grant as the capability
-
Actor B can now use the URI of that new Grant
as the capability when it sends activities that access or
manipulate resource R.
3.6.2.3. Requesting access using Join activities
When an actor A wishes to request access to resource R (where the resource
actor who manages R isn’t A), then actor A SHOULD use a Join activity, and the following steps. There are two options detailed
below, depending on whether actor A has been previously given a Grant authorizing it to gain access to resource R without
needing someone else to approve. For example, perhaps actor A already has
some access to a resource collection to which R belongs, and that access
allows A to freely Join
R without needing to wait for human approval.
*Option 1: Actor *A already has a Grant
allowing it to gain access to R without external approval:**
-
Actor A publishes and delivers a Join, at least to the resource actor of R, with the relevant capability it has (see § 7.1.2 Join for details on the properties to use)
-
The resource actor of R receives the
Join
and:-
Verifies the
Join
is authorized, as described above in Verifying an invocation -
Publishes and delivers a Grant activity (see § 7.1.3 Grant for more details on the properties) where:
-
-
A is now considered a collaborator in R!
-
If R is a Project or a Team, additional steps occur:
-
A, seeing R's Grant, publishes a delegate-Grant in which the target is R and capability is R's Grant
-
From now on, whenever R wishes to extend a Grant chain to A, it uses A's delegate-Grant as the capability
-
Actor A can now use the URI of that new Grant
as the capability when it sends activities that access or
manipulate resource R.
*Option 2: Actor *A doesn’t have (or chooses not to use) a Grant
allowing
it to gain access to R without external approval:**
-
Actor A publishes and delivers a Join, at least to the resource actor of R (see § 7.1.2 Join for details on the properties to use)
-
If some actor B, that has previously received a
Grant
from the resource actor of R authorizing it to approve joins, sees theJoin
sent by actor A and decides to approve it, then actor B publishes and delivers (at least to the resource actor of R) an Accept activity where:-
object specifies the
Join
sent by actor A -
capability is the
Grant
mentioned above, authorizing to approve or deny Joins
-
-
The resource actor of R receives the
Join
and theAccept
and:-
Verifies the
Accept
is authorized, as described above in Verifying an invocation -
Verifies that the
Accept
’s object specifies theJoin
-
Publishes and delivers a Grant activity (see § 7.1.3 Grant for more details on the properties) where:
-
-
A is now considered a collaborator in R!
-
If R is a Project or a Team, additional steps occur:
-
A, seeing R's Grant, publishes a delegate-Grant in which the target is R and capability is R's Grant
-
From now on, whenever R wishes to extend a Grant chain to A, it uses A's delegate-Grant as the capability
-
Actor A can now use the URI of that new Grant
as the capability when it sends activities that access or
manipulate resource R.
In step 2, actor B may choose to deny the request of actor A, by sending a Reject activity (at least to the resource actor of R) where:
-
object specifies the
Join
that actor A sent -
capability is the
Grant
mentioned in step 2, authorizing actor B to approve or deny Joins
If the resource actor of R receives the Reject
:
-
It MUST verify the
Reject
is authorized, as described above in Verifying an invocation -
it MUST verify that the
Reject
’s object specifies theJoin
-
Consider this
Join
request canceled: If actor B, or some other actor C, tries again toAccept
theJoin
, then:-
The resource actor MUST NOT send a
Grant
to actor A, even if theAccept
is authorized -
The resource actor MAY publish and deliver a
Reject
activity, at least to the actor that sent theAccept
, where object specifies theAccept
-
-
It SHOULD publish and deliver a
Reject
activity, at least to actor A, where object specifies theJoin
that actor A sent
So, once a Join
is rejected (using an authorized Reject
), it cannot be
accepted. But actor A MAY send a new Join
, which could then possibly get
accepted.
3.6.3. Revoking access
3.6.3.1. Taking away access using Remove activities
When an actor A wishes to cancel the membership of another actor B (who isn’t A) in a shared resource R, invalidating any active § 7.1.3 Grants that the resource actor of R has granted to actor B, then actor A SHOULD use a Remove activity, and the following steps:
-
Actor A publishes and delivers a Remove, at least to actor B and to the resource actor of R, with a relevant capability (see § 7.2.1 Remove for details on the properties to use)
-
The resource actor of R receives the
Remove
and:-
Verifies the
Remove
is authorized, as described above in Verifying an invocation -
Verifies that actor B indeed has active
Grant
s for accessing resource R -
Marks those Grants as disabled in its internal state
-
Publishes and delivers a § 7.2.3 Revoke activity, as described above in Revoking a Grant, where fulfills specifies the
Remove
-
Actor B SHOULD no longer use the URI of any Grant
that has been disabled as
the capability when it sends activities that access or
manipulate resource R.
3.6.3.2. Waiving access using Leave activities
When an actor A wishes to cancel their membership in a shared resource R (where the resource actor who manages R isn’t A), invalidating any active § 7.1.3 Grants that the resource actor of R has granted to actor A, then actor A SHOULD use a Leave activity, and the following steps:
-
Actor A publishes and delivers a Leave, at least to the resource actor of R (see § 7.2.2 Leave for details on the properties to use)
-
The resource actor of R receives the
Leave
and:-
Verifies that actor A indeed has active
Grant
s for accessing resource R -
Marks those Grants as disabled in its internal state
-
Publishes and delivers a § 7.2.3 Revoke activity, as described above in Revoking a Grant, where fulfills specifies the
Leave
-
Actor A SHOULD no longer use the URI of any Grant
that has been disabled as
the capability when it sends activities that access or
manipulate resource R.
3.6.3.3. Requesting to disable specific Grants using Undo
When an actor A wishes to deactivate a specific § 7.1.3 Grant activity
(or multiple Grant
s), providing access to view or manipulate some resource R (where the resource actor of R isn’t A), then actor A SHOULD use an Undo activity, and the following steps. The actor B to whom
access-to-resource-R was given by the Grant
may be actor A itself, or
some other actor, as long as actor A is authorized by the resource actor of R to deactivate that Grant
.
NOTE: Upon a successful Undo
, if actor B doesn’t have any active Grants
left, that allow access to resource R, then the resource actor of R MAY
remove actor B's membership in R, or it MAY consider actor B a member
without access.
-
Actor A publishes and delivers an Undo, at least to the resource actor of R (see § 7.2.4 Undo a Grant for details on the properties to use)
-
The resource actor of R receives the
Undo
and:-
Verifies the
Undo
is authorized, as described above in Verifying an invocation -
Verifies that actor B indeed has all the active
Grant
s for accessing resource R, that are listed as objects of theUndo
(if more than oneGrant
is listed, the target of all theGrant
s MUST be identical) -
Marks all of those Grants as disabled in its internal state
-
Publishes and delivers a § 7.2.3 Revoke activity, at least to actors A and B, as described above in Revoking a Grant, where:
-
Actor B SHOULD no longer use the URI of any Grant
that has been disabled as
the capability when it sends activities that access or
manipulate resource R.
3.6.4. Example
Aviva creates a new Repository for her 3D Tree Growth Simulation software:
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://forge.community/users/aviva/outbox/oU6QGAqr-create-treesim" , "type" : "Create" , "actor" : "https://forge.community/users/aviva" , "to" : [ "https://forge.community/users/aviva/followers" ], "object" : { "id" : "https://forge.community/repos/treesim" , "type" : "Repository" , "name" : "Tree Growth 3D Simulation" , "summary" : "A graphical simulation of trees growing" } }
The newly created treesim Repository
automatically sends back a Grant
to
Aviva, allowing her full access to the repo:
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://forge.community/repos/treesim/outbox/2NwyPWMX-grant-admin-to-aviva" , "type" : "Grant" , "actor" : "https://forge.community/repos/treesim" , "to" : [ "https://forge.community/aviva" , "https://forge.community/aviva/followers" ], "object" : "admin" , "context" : "https://forge.community/repos/treesim" , "target" : "https://forge.community/aviva" , "fulfills" : "https://forge.community/users/aviva/outbox/oU6QGAqr-create-treesim" , "allows" : "invoke" , "endTime" : "2023-12-31T23:00:00-08:00" }
Aviva can now use this Grant
, e.g. to update the repo’s description text:
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://forge.community/users/aviva/outbox/RmTygyuj" , "type" : "Update" , "actor" : "https://forge.community/users/aviva" , "to" : [ "https://forge.community/users/aviva/followers" , "https://forge.community/repos/treesim" , "https://forge.community/repos/treesim/followers" ], "object" : { "id" : "https://forge.community/repos/treesim" , "type" : "Repository" , "name" : "Tree Growth 3D Simulation" , "summary" : "Tree growth 3D simulator for my nature exploration game" }, "capability" : "https://forge.community/repos/treesim/outbox/2NwyPWMX-grant-admin-to-aviva" }
Aviva wants to keep track of events related to the treesim repo:
{ "@context" : "https://www.w3.org/ns/activitystreams" , "id" : "https://forge.community/users/aviva/outbox/gqtpAhm2" , "type" : "Follow" , "actor" : "https://forge.community/users/aviva" , "to" : "https://forge.community/repos/treesim" , "object" : "https://forge.community/repos/treesim" , }
Aviva can invite Luke to have access to the treesim repo:
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://forge.community/users/aviva/outbox/qfrEGqnC-invite-luke" , "type" : "Invite" , "actor" : "https://forge.community/users/aviva" , "to" : [ "https://forge.community/aviva/followers" , "https://forge.community/repos/treesim" , "https://forge.community/repos/treesim/followers" , "https://software.site/people/luke" , "https://software.site/people/luke/followers" ], "instrument" : "maintain" , "target" : "https://forge.community/repos/treesim" , "object" : "https://software.site/people/luke" , "capability" : "https://forge.community/repos/treesim/outbox/2NwyPWMX-grant-admin-to-aviva" }
And it appears that Luke accepts the invitation:
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://software.site/people/luke/activities/mEYYmt8u" , "type" : "Accept" , "actor" : "https://software.site/people/luke" , "to" : [ "https://forge.community/aviva" , "https://forge.community/aviva/followers" , "https://forge.community/repos/treesim" , "https://forge.community/repos/treesim/followers" , "https://software.site/people/luke/followers" ], "object" : "https://forge.community/users/aviva/outbox/qfrEGqnC-invite-luke" }
Seeing the Invite
and the Accept
, the treesim repo sends Luke a Grant
giving him the access that Aviva offered, and which he accepted:
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://forge.community/repos/treesim/outbox/D5uod3pz-grant-maintainer-to-luke" , "type" : "Grant" , "actor" : "https://forge.community/repos/treesim" , "to" : [ "https://forge.community/aviva" , "https://forge.community/aviva/followers" , "https://forge.community/repos/treesim/followers" , "https://software.site/people/luke" , "https://software.site/people/luke/followers" ], "object" : "maintain" , "context" : "https://forge.community/repos/treesim" , "target" : "https://software.site/people/luke" , "fulfills" : "https://forge.community/users/aviva/outbox/qfrEGqnC-invite-luke" , "allows" : "invoke" , "endTime" : "2023-12-31T23:00:00-08:00" }
Luke can now use this Grant
, e.g. to delete some old obsolete branch of the treesim repo:
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://software.site/people/luke/activities/vShj2aIe" , "type" : "Delete" , "actor" : "https://software.site/people/luke" , "to" : [ "https://forge.community/repos/treesim" , "https://forge.community/repos/treesim/followers" , "https://software.site/people/luke/followers" ], "object" : "https://forge.community/repos/treesim/branches/fixes-for-release-0.1.3" , "origin" : "https://forge.community/repos/treesim" , "capability" : "https://forge.community/repos/treesim/outbox/D5uod3pz-grant-maintainer-to-luke" }
Celine requests to have developer access to the treesim repo:
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://dev.online/@celine/sent/v5Qvd6bB-celine-join" , "type" : "Join" , "actor" : "https://dev.online/@celine" , "to" : [ "https://forge.community/repos/treesim" , "https://forge.community/repos/treesim/followers" , "https://dev.online/@celine/followers" ], "object" : "https://forge.community/repos/treesim" , "instrument" : "write" }
Aviva sees the Join
request, talks with Celine and decides to approve her
request:
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://forge.community/users/aviva/outbox/PzRtDydu" , "type" : "Accept" , "actor" : "https://forge.community/users/aviva" , "to" : [ "https://forge.community/repos/treesim" , "https://forge.community/repos/treesim/followers" , "https://dev.online/@celine" , "https://dev.online/@celine/followers" ], "object" : "https://dev.online/@celine/sent/v5Qvd6bB-celine-join" , "capability" : "https://forge.community/repos/treesim/outbox/2NwyPWMX-grant-admin-to-aviva" }
Seeing the Join
and the Accept
, the treesim repo sends Celine a Grant
giving her the access that she requested, and which Aviva approved:
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://forge.community/repos/treesim/outbox/D5uod3pz-grant-developer-to-celine" , "type" : "Grant" , "actor" : "https://forge.community/repos/treesim" , "to" : [ "https://forge.community/aviva" , "https://forge.community/repos/treesim/followers" , "https://dev.online/@celine" , "https://dev.online/@celine/followers" ], "object" : "write" , "context" : "https://forge.community/repos/treesim" , "target" : "https://dev.online/@celine" , "fulfills" : "https://dev.online/@celine/sent/v5Qvd6bB-celine-join" , "allows" : "invoke" , "endTime" : "2023-12-31T23:00:00-08:00" }
Celine can now use this Grant
to access the treesim repo.
3.7. Adding and Removing Team Members
Minimal required role: admin
This is done using the processes described in the § 3.6.2 Granting access section. In particular, once the new member M sends the team T the delegate-Grant, T SHOULD use it to send M extension-Grants of:
-
Every authorized (by a valid delegate-Grant) Grant whose allows is distribute, that T has received from any of its parent teams
-
Every authorized (by a valid delegate-Grant) Grant whose allows is distribute, that T has received from any of the projects it has direct access to
-
Every authorized (by a valid delegate-Grant) Grant whose allows is distribute, that T has received from any of the components it has direct access to
3.8. Adding and Removing Project Members
Minimal required role: admin
This is done using the processes described in the § 3.6.2 Granting access section. In particular, once the new member M sends the project J the delegate-Grant, J SHOULD use it to send M extension-Grants of:
-
Every authorized (by a valid delegate-Grant) Grant whose allows is gatherAndConvey, that J has received from any of its child projects
-
Every authorized (by a valid delegate-Grant) Grant whose allows is gatherAndConvey, that J has received from any of its components
3.9. Associating Projects and Components
Minimal required role: admin
Adding and removing a component to/from a project each have 2 versions: The "component side" version allows an actor to initiate the action using admin access to the component, while the "project side" version allows to initiate the action using admin access to the project.
Whenever authorization is mentioned below, it SHOULD be done using the invocation verification process.
3.9.1. Adding a component to a project - component side
Assuming:
-
A project P
-
A component C
-
A person with admin access to C, Alice
-
A person with admin access to P, Bob
Alice wants to add component C to project P. The exchange of activities SHOULD be as follows:
-
Alice sends an Add activity in which:
-
object is P
-
instrument is the maximal Role that Alice would like to allow for people (and bots) when authorizing their manipulation of C by their access in P (normally it would be admin, perhaps sometimes maintain)
-
capability is the URI of a Grant that authorizes admin access to C
-
-
C, seeing and authorizing the Add, publishes an Accept where object is the Add’s URI
-
Bob, seeing the Add and the Accept, sends an Accept where:
-
object is the Add’s URI
-
capability is the URI of a Grant that authorizes admin access to P
-
-
P, seeing the previous 3 activities and authorizing Bob’s Accept, publishes a delegate-Grant in which the target is C
-
C, seeing P's Grant, sends a start-Grant where:
-
target specifies P
-
object specifies the role specified in the Add’s instrument
-
capability is the URI of the delegate-Grant
-
P, seeing and authorizing C's Grant, now extends the Grant chain as relevant, to its members and parent projects
3.9.2. Removing a component from a project - component side
Assuming:
-
A project P with a component C
-
A person with admin access to C, Alice
Alice wants to ask component C to remove itself from project P. The exchange of activities SHOULD be as follows:
-
Alice sends a Remove activity where:
-
object is P
-
capability is the URI of a Grant that authorizes admin access to C
-
-
C, seeing and authorizing the Remove, publishes a Revoke where object specifies the active start-Grant it had sent to P (and C now considers that Grant revoked and no longer considers itself as a component of P)
-
P, seeing the Remove and the Revoke, publishes a Revoke where object specifies the active delegate-Grant it had sent to C (and P now considers that Grant revoked and no longer considers C a component of it)
3.9.3. Adding a component to a project - project side
Assuming:
-
A project P
-
A component C
-
A person with admin access to C, Alice
-
A person with admin access to P, Bob
Bob wants to add component C to project P. The exchange of activities SHOULD be as follows:
-
Bob sends an Add activity in which:
-
object is C
-
target is the URI of P's components collection
-
instrument is the maximal Role that Bob would like to allow for people (and bots) when authorizing their manipulation of C by their access in P (normally it would be admin, perhaps sometimes maintain)
-
capability is the URI of a Grant that authorizes admin access to P
-
-
P, seeing and authorizing the Add, publishes an Accept where object is the Add’s URI
-
Alice, seeing the Add and the Accept, sends an Accept where:
-
object is the Add’s URI
-
capability is the URI of a Grant that authorizes admin access to C
-
-
C, seeing the previous 3 activities and authorizing Alice’s Accept, sends an Accept where object is the Add’s URI
-
P, seeing C's Accept, publishes a delegate-Grant in which the target is C
-
C, seeing P's Grant, sends a start-Grant where:
-
target specifies P
-
object specifies the role specified in the Add’s instrument
-
capability is the URI of the delegate-Grant
-
P, seeing and authorizing C's Grant, now extends the Grant chain as relevant, to its members and parent projects
3.9.4. Removing a component from a project - project side
Assuming:
-
A project P with a component C
-
A person with admin access to P, Bob
Bob wants to ask project P to remove component C from it. The exchange of activities SHOULD be as follows:
-
Bob sends a Remove activity where:
-
object is C
-
origin is the URI of P's components collection
-
capability is the URI of a Grant that authorizes admin access to P
-
-
P, seeing and authorizing the Remove, publishes a Revoke where object specifies the active delegate-Grant it had sent to C (and P now considers that Grant revoked and no longer considers C a component of it)
-
C, seeing the Remove and the Revoke, publishes a Revoke where object specifies the active start-Grant it had sent to P (and C now considers that Grant revoked and no longer considers itself as a component of P)
3.10. Adding and Removing Children and Parents to Projects and Teams
Minimal required role: admin
Like most cooperation between ForgeFed actors, the parent-child link is based on mutual consent:
-
To form the link, both projects/teams must explicitly agree to it
-
To remove the link, it’s enough for one of them to withdraw its consent
Parent-child links are a part of the Grant delegation system, in which the flow is:
-
Components initiate delegation, to:
-
The projects they belong to
-
Teams which have access to them
-
-
Projects delegate to their:
-
Direct collaborators
-
Parent projects
-
Teams which have access to them
-
-
Teams delegate to their:
-
Direct collaborators
-
Child teams
-
Once a parent-child link is formed, delegations start happening through the link. This is described in more detail below.
Each delegation within this flow therefore has a "source" side, which sends the delegation, and a "destination" side, which receives it and possibly delegates it further.
In a parent-child link, therefore, there is a "source" side and a "destination" side. For projects, the child is the source and the parent is the destination (because projects delegate to their parents, once a link is formed). For teams, the parent is the source and the child is the destination (because teams delegate to their children, once a link is formed).
Since either side of the link can initiate the process, and since delegation flow occurs in one direction, there are essentially two versions of the process:
-
Process initiated by the source side (i.e. a project asking to have a parent, or a team asking to have a child)
-
Process initiated by the destination side (i.e. a project asking to have a child, or a team asking to have a parent)
In the Add activity that initiates the process, the initiating side is determined by the target property. The actor to whom the collection specified by target belongs, is the initiating side. The other side of the link is specified in the object property.
Whenever authorization is mentioned below, it SHOULD be done using the invocation verification process.
3.10.1. Forming a project child-parent link
3.10.1.1. Initiated by the parent
Assuming:
-
A project P
-
A project C
-
A person with admin access to C, Celia
-
A person with admin access to P, Philip
Philip wants C to become a child of P (which means P will be a parent of C). The exchange of activities SHOULD be as follows:
-
Philip sends an Add activity in which:
-
object is C
-
target is the URI of P's subprojects (i.e. children) collection
-
instrument is the maximal Role that Philip would like to allow for people (and bots) when authorizing their manipulation of C by their access in P (normally it would be admin, perhaps sometimes maintain)
-
capability is the URI of a Grant that authorizes Philip’s admin access to P
-
-
P, seeing and authorizing the Add, publishes an Accept where object is the Add’s URI
-
Celia, seeing the Add and the Accept, sends an Accept where:
-
object is the Add’s URI
-
capability is the URI of a Grant that authorizes Celia’s admin access to C
-
-
C, seeing the Add and authorizing Celia’s Accept, publishes an Accept where object is the Add’s URI
-
P, seeing C's Accept, publishes a delegate-Grant in which the target is C, and now considers C a child and lists C in the subprojects collection
-
C, seeing P's Grant, now considers P a parent and lists P in the context (i.e. parents) collection
Now C sends delegation Grant activities, see the § 3.10.1.3 Delegation step section below.
3.10.1.2. Initiated by the child
Assuming:
-
A project P
-
A project C
-
A person with admin access to C, Celia
-
A person with admin access to P, Philip
Celia wants C to become a child of P (which means P will be a parent of C). The exchange of activities SHOULD be as follows:
-
Celia sends an Add activity in which:
-
object is P
-
instrument is the maximal Role that Celia would like to allow for people (and bots) when authorizing their manipulation of C by their access in P (normally it would be admin, perhaps sometimes maintain)
-
capability is the URI of a Grant that authorizes Celia’s admin access to C
-
-
C, seeing and authorizing the Add, publishes an Accept where object is the Add’s URI
-
Philip, seeing the Add and the Accept, sends an Accept where:
-
object is the Add’s URI
-
capability is the URI of a Grant that authorizes Philip’s admin access to P
-
-
P, seeing the Add, seeing C's Accept, and authorizing Philip’s Accept, publishes a delegate-Grant in which the target is C, and now considers C a child and lists C in the subprojects collection
-
C, seeing P's Grant, now considers P a parent and lists P in the context (i.e. parents) collection
Now C sends delegation Grant activities, see the § 3.10.1.3 Delegation step section below.
3.10.1.3. Delegation step
C now sends Grant activities, which P delegates further by sending its own Grant activities, as described in § 3.6.1.6 Extending a delegation chain, to its member humans, member teams, and parent projects.
-
C sends a start-Grant where:
-
target specifies P
-
object specifies the role specified in the Add’s instrument
-
capability is the URI of the delegate-Grant from step 5 or 4 above
-
For each delegation Grant g that C has received from its components and child projects, C sends an extension-Grant where:
-
actor specifies C
-
target specifies P
-
object specifies the lower role among the one specified by the Add’s instrument, and the one specified by g's object
-
capability is the URI of the delegate-Grant from step 5 or 4 above
-
delegates specifies g's URI
-
When P sees these Grants, it delegates them further, as mentioned above.
In addition, as long as the parent-child link remains active, whenever C receives a delegation Grant from any of its components or children, it SHOULD send P an extension-Grant as described above, and P SHOULD extend it further.
3.10.2. Removing a project child-parent link
3.10.2.1. Initiated by the child
Assuming:
-
Projects P and C, where P is a parent of C
-
A person with admin access to C, Celia
Celia wants C to stop being a child of P (which means P will stop being a parent of C). The exchange of activities SHOULD be as follows:
-
Celia sends an Remove activity in which:
-
object is P
-
capability is the URI of a Grant that authorizes Celia’s admin access to C
-
-
C, seeing and authorizing the Remove, publishes an Accept where object is the Add’s URI
-
P, seeing the Remove and the Accept, publishes a Revoke activity in which the object is the delegate-Grant it had sent to C, and now considers that Grant revoked, and removes C from its subprojects collection
-
C, seeing P's Revoke, removes P from its context (i.e. parents) collection
Now, for each Grant g that P has published, as an extension of a Grant it had received from C:
-
P sends (to g's target) a Revoke activity whose object specifies g's URI
-
P considers g invalidated
-
The recipient of the Revoke, if it further published extensions of g, now similarly publishes Revoke activities and considers those extension Grants invalid
3.10.2.2. Initiated by the parent
Assuming:
-
Projects P and C, where P is a parent of C
-
A person with admin access to P, Philip
Philip wants C to stop being a child of P (which means P will stop being a parent of C). The exchange of activities SHOULD be as follows:
-
Philip sends an Remove activity in which:
-
object is C
-
origin is the URI of P's subprojects (i.e. children) collection
-
capability is the URI of a Grant that authorizes Philip’s admin access to P
-
-
P, seeing and authorizing the Remove, publishes a Revoke activity in which the object is the delegate-Grant it had sent to C, and now considers that Grant revoked, and removes C from its subprojects collection
-
C, seeing P's Revoke, removes P from its context (i.e. parents) collection, and MAY publish an Accept (whose object is the Remove) to notify its followers
Now, for each Grant g that P has published, as an extension of a Grant it had received from C:
-
P sends (to g's target) a Revoke activity whose object specifies g's URI
-
P considers g invalidated
-
The recipient of the Revoke, if it further published extensions of g, now similarly publishes Revoke activities and considers those extension Grants invalid
3.10.3. Forming a team child-parent link
3.10.3.1. Initiated by the parent
Assuming:
-
A team P
-
A team C
-
A person with admin access to C, Celia
-
A person with admin access to P, Philip
Philip wants C to become a child of P (which means P will be a parent of C). The exchange of activities SHOULD be as follows:
-
Philip sends an Add activity in which:
-
object is C
-
target is the URI of P's subteams (i.e. children) collection
-
instrument is the maximal Role that Philip would like to allow for people (and bots) when authorizing their manipulation of C by their access in P (normally it would be admin, perhaps sometimes maintain)
-
capability is the URI of a Grant that authorizes Philip’s admin access to P
-
-
P, seeing and authorizing the Add, publishes an Accept where object is the Add’s URI
-
Celia, seeing the Add and the Accept, sends an Accept where:
-
object is the Add’s URI
-
capability is the URI of a Grant that authorizes Celia’s admin access to C
-
-
C, seeing the Add, seeing P's Accept, and authorizing Celia’s Accept, publishes a delegate-Grant in which the target is P, and now considers P a parent and lists P in the context (i.e. parents) collection
-
P, seeing C's Grant, now considers C a parent and lists C in the subteams collection
Now P sends delegation Grant activities, see the § 3.10.3.3 Delegation step section below.
3.10.3.2. Initiated by the child
Assuming:
-
A team P
-
A team C
-
A person with admin access to C, Celia
-
A person with admin access to P, Philip
Celia wants C to become a child of P (which means P will be a parent of C). The exchange of activities SHOULD be as follows:
-
Celia sends an Add activity in which:
-
object is P
-
instrument is the maximal Role that Celia would like to allow for people (and bots) when authorizing their manipulation of C by their access in P (normally it would be admin, perhaps sometimes maintain)
-
capability is the URI of a Grant that authorizes Celia’s admin access to C
-
-
C, seeing and authorizing the Add, publishes an Accept where object is the Add’s URI
-
Philip, seeing the Add and the Accept, sends an Accept where:
-
object is the Add’s URI
-
capability is the URI of a Grant that authorizes Philip’s admin access to P
-
-
P, seeing the Add, seeing C's Accept, and authorizing Philip’s Accept, publishes an Accept where object is the Add’s URI
-
C, seeing P's Accept, publishes a delegate-Grant in which the target is P, and now considers P a parent and lists P in the context (i.e. parents) collection
-
P, seeing C's Grant, now considers C a child and lists C in the subteams collection
Now P sends delegation Grant activities, see the § 3.10.3.3 Delegation step section below.
3.10.3.3. Delegation step
P now sends Grant activities, which C delegates further by sending its own Grant activities, as described in § 3.6.1.6 Extending a delegation chain, to its member humans and child teams.
-
P sends a start-Grant where:
-
target specifies C
-
object specifies the role specified in the Add’s instrument
-
allows is distribute
-
capability is the URI of the delegate-Grant from step 4 or 5 above
-
For each delegation Grant g that P has received from its projects, components or parent teams, P sends an extension-Grant where:
-
actor specifies P
-
target specifies C
-
object specifies the lower role among the one specified by the Add’s instrument, and the one specified by g's object
-
allows is distribute
-
capability is the URI of the delegate-Grant from step 4 or 5 above
-
delegates specifies g's URI
-
When C sees these Grants, it delegates them further, as mentioned above.
In addition, as long as the parent-child link remains active, whenever P receives a delegation Grant from any of its projects, components or parents, it SHOULD send C an extension-Grant as described above, and C SHOULD extend it further.
3.10.4. Removing a team child-parent link
3.10.4.1. Initiated by the child
Assuming:
-
Teams P and C, where P is a parent of C
-
A person with admin access to C, Celia
Celia wants C to stop being a child of P (which means P will stop being a parent of C). The exchange of activities SHOULD be as follows:
-
Celia sends an Remove activity in which:
-
object is P
-
capability is the URI of a Grant that authorizes Celia’s admin access to C
-
-
C, seeing and authorizing the Remove, publishes a Revoke activity in which the object is the delegate-Grant it had sent to P, and now considers that Grant revoked, and removes P from its context (i.e. parents) collection
-
P, seeing C's Revoke, removes C from its subteams collection, and MAY publish an Accept (whose object is the Remove) to notify its followers
Now, for each Grant g that C has published, as an extension of a Grant it had received from P:
-
C sends (to g's target) a Revoke activity whose object specifies g's URI
-
C considers g invalidated
-
The recipient of the Revoke, if it further published extensions of g, now similarly publishes Revoke activities and considers those extension Grants invalid
3.10.4.2. Initiated by the parent
Assuming:
-
Teams P and C, where P is a parent of C
-
A person with admin access to P, Philip
Philip wants C to stop being a child of P (which means P will stop being a parent of C). The exchange of activities SHOULD be as follows:
-
Philip sends an Remove activity in which:
-
object is C
-
capability is the URI of a Grant that authorizes Philip’s admin access to P
-
-
P, seeing and authorizing the Remove, publishes an Accept where object is the Add’s URI
-
C, seeing the Remove and the Accept, publishes a Revoke activity in which the object is the delegate-Grant it had sent to P, and now considers that Grant revoked, and removes P from its context (i.e. parents) collection
-
P, seeing C's Revoke, removes C from its subteams collection
Now, for each Grant g that C has published, as an extension of a Grant it had received from P:
-
C sends (to g's target) a Revoke activity whose object specifies g's URI
-
C considers g invalidated
-
The recipient of the Revoke, if it further published extensions of g, now similarly publishes Revoke activities and considers those extension Grants invalid
3.11. Enabling and Disabling Team Access to a Resource
Minimal required role: admin
As described in previous sections, resource actors (Teams, Projects and components) can have direct collaborators (usually Persons and utility bots), through the direct granting process. Team actors, however, have a special kind of being collaborators: Rather than receiving a Grant they can invoke themselves, they receive Grants that they delegate to their members, and recursively delegate to their child teams.
This kind of collaboration link is described in this section.
Like most cooperation between ForgeFed actors, the link is based on mutual consent:
-
To form the link, both the team and the resource must explicitly agree to it
-
To remove the link, it’s enough for one of them to withdraw its consent
These links are a part of the Grant delegation system, in which the flow is:
-
Components initiate delegation, to:
-
The projects they belong to
-
Teams which have access to them
-
-
Projects delegate to their:
-
Direct collaborators
-
Parent projects
-
Teams which have access to them
-
-
Teams delegate to their:
-
Direct collaborators
-
Child teams
-
Once a link is formed, delegations start happening through the link. This is described in more detail below.
Since either side of the link can initiate the process, and since delegation flow occurs in one direction, there are essentially two versions of the process:
-
Process initiated by the resource side (i.e. a resource asking to give access a team)
-
Process initiated by the team side (i.e. a team asking to have access to a resource)
In the Add activity that initiates the process, the initiating side is determined by the target property. The actor to whom the collection specified by target belongs, is the initiating side. The other side of the link, receiving the Add, is specified in the object property.
Whenever authorization is mentioned below, it SHOULD be done using the invocation verification process.
3.11.1. Forming a team-resource link
3.11.1.1. Initiated by the resource
Assuming:
-
A team T
-
A resource actor R
-
A person with admin access to T, Tessa
-
A person with admin access to R, Robin
Robin wants T to gain access to R. The exchange of activities SHOULD be as follows:
-
Robin sends an Add activity in which:
-
object is T
-
instrument is the maximal Role that Robin would like to allow for people (and bots) when authorizing their manipulation of R by their access in T (normally it would be admin, perhaps sometimes maintain)
-
capability is the URI of a Grant that authorizes Robin’s admin access to R
-
-
R, seeing and authorizing the Add, publishes an Accept where object is the Add’s URI
-
Tessa, seeing the Add and the Accept, sends an Accept where:
-
object is the Add’s URI
-
capability is the URI of a Grant that authorizes Celia’s admin access to T
-
-
T, seeing the Add, seeing R's Accept, and authorizing Tessa’s Accept, publishes a delegate-Grant in which the target is R, and now considers R an accessible resource and lists R in the teamResources collection
-
R, seeing T's Grant, now considers R a collaborator and lists R in the teams collection
Now R sends delegation Grant activities, see the § 3.11.1.3 Delegation step section below.
3.11.1.2. Initiated by the team
Assuming:
-
A team T
-
A resource actor R
-
A person with admin access to T, Tessa
-
A person with admin access to R, Robin
Tessa wants T to gain access to R. The exchange of activities SHOULD be as follows:
-
Tessa sends an Add activity in which:
-
object is R
-
target is the URI of T's teamResources collection
-
instrument is the maximal Role that Tessa would like to have and allow for people (and bots) when authorizing their manipulation of R by their access in T (normally it would be admin, perhaps sometimes maintain)
-
capability is the URI of a Grant that authorizes Tessa’s admin access to T
-
-
T, seeing and authorizing the Add, publishes an Accept where object is the Add’s URI
-
Robin, seeing the Add and the Accept, sends an Accept where:
-
object is the Add’s URI
-
capability is the URI of a Grant that authorizes Robin’s admin access to R
-
-
R, seeing the Add, seeing T's Accept, and authorizing Robin’s Accept, publishes an Accept where object is the Add’s URI
-
T, seeing R's Accept, publishes a delegate-Grant in which the target is R, and now considers R an accessible resource and lists R in the teamResources collection
-
R, seeing T's Grant, now considers T a collaborator and lists T in the teams collection
Now R sends delegation Grant activities, see the § 3.11.1.3 Delegation step section below.
3.11.1.3. Delegation step
R now sends Grant activities, which T delegates further by sending its own Grant activities, as described in § 3.6.1.6 Extending a delegation chain, to its member humans and child teams.
-
R sends a start-Grant where:
-
target specifies T
-
object specifies the role specified in the Add’s instrument
-
allows is distribute
-
capability is the URI of the delegate-Grant from step 4 or 5 above
-
If R is a Project, then for each delegation Grant g that R has received from its components or children, R sends an extension-Grant where:
-
actor specifies R
-
target specifies T
-
object specifies the lower role among the one specified by the Add’s instrument, and the one specified by g's object
-
allows is distribute
-
capability is the URI of the delegate-Grant from step 4 or 5 above
-
delegates specifies g's URI
-
When T sees these Grants, it delegates them further, as mentioned above.
In addition, as long as the team-resource link remains active, whenever R receives a delegation Grant from any of its components or children, it SHOULD send T an extension-Grant as described above, and T SHOULD extend it further.
3.11.2. Removing a team-resource link
3.11.2.1. Initiated by the resource
Assuming:
-
A team T, that has access to a resource actor R
-
A person with admin access to R, Robin
Robin wants T to stop being a collaborator in R. The exchange of activities SHOULD be as follows:
-
Robin sends a Remove activity in which:
-
object is T
-
capability is the URI of a Grant that authorizes Robin’s admin access to R
-
-
R, seeing and authorizing the Remove, publishes an Accept where object is the Remove’s URI, and R removes T from its teams collection
-
T, seeing the Remove and the Accept, publishes a Revoke activity in which the object is the delegate-Grant it had sent to R, and now considers that Grant revoked, and removes R from its teamResources collection
Now, for each Grant g that T has published, as an extension of a Grant it had received from R:
-
T sends (to g's target) a Revoke activity whose object specifies g's URI
-
T considers g invalidated
-
The recipient of the Revoke, if it further published extensions of g, now similarly publishes Revoke activities and considers those extension Grants invalid
3.11.2.2. Initiated by the team
Assuming:
-
A team T, that has access to a resource actor R
-
A person with admin access to T, Tessa
Tessa wants T to stop being a collaborator in R. The exchange of activities SHOULD be as follows:
-
Tessa sends a Remove activity in which:
-
object is R
-
origin is the URI of T's teamResources collection
-
capability is the URI of a Grant that authorizes Tessa’s admin access to T
-
-
T, seeing and authorizing the Remove, publishes a Revoke activity in which the object is the delegate-Grant it had sent to R, and now considers that Grant revoked, and removes R from its teamResources collection
-
R, seeing T's Revoke, removes T from its teams collection, and MAY publish an Accept (whose object is the Remove) to notify its followers
Now, for each Grant g that T has published, as an extension of a Grant it had received from R:
-
T sends (to g's target) a Revoke activity whose object specifies g's URI
-
T considers g invalidated
-
The recipient of the Revoke, if it further published extensions of g, now similarly publishes Revoke activities and considers those extension Grants invalid
3.12. Creating Resource Actors
Minimal required role: write
There are 2 types of actors whose process of creation is a special case:
-
Person: Created by registering an account
-
Factory: Can be created by a C2S Create activity, where the access control to this operation is server-specific (for example perhaps only server administrators can create Factories)
All the other actor types, the resouce actors besides Factory, MUST be created via a Factory actor.
A given factory specifies via the availableActorTypes the specific types it supports.
Assuming:
-
A factory F
-
A person with write access to F, Philip
Philip wants to create a new actor, of a type supported by F. The exchange of activities SHOULD be as follows:
-
Philip sends a Create activity in which:
-
object contains the properties of the new actor to be created
-
origin is the URI of F
-
capability is the URI of a Grant that authorizes Philip’s access to F
-
-
F, seeing and authorizing the Create, publishes an Accept where object is the Create’s URI and result is the URI of the newly created actor A
-
A, upon its creation, publishes a direct-Grant in which the target is Philip and object is admin, thus giving Philip full access to manage A
3.13. Editing an Object
Minimal required role: It varies
The problem with the Update activity is that it contains a full description of the updated object. This means it’s not a successful candidate for describing clear atomic change requests. Since there is no standard solution on the Fediverse at the time of writing, ForgeFed for now introduces its own solution:
A new actvity type, Edit.
It is intentionally not named Patch, as that name is already in use in ForgeFed under a different meaning. See Patch.
NOTE: Each resource type specifies the fields that it allows actors to edit via the Edit activity. For example, for a Note this would be the source and content.
Assuming:
-
A resource actor R,
-
A resource r managed by R
-
A person with edit access to r, Celia
Celia wants to edit certain properties of r, which are meant to be edited using the Edit activity. The exchange of activities SHOULD be as follows:
-
Celia sends an Edit activity in which:
-
object is an object in which:
-
id is the URI of r
-
The other fields are the ones Celia wants to set to new values
-
-
context is the URI of R
-
(optionally) capability is the URI of a Grant that authorizes Celia’s edit access to r
-
-
R, seeing the Edit and authorizing Celia’s access and changes, publishes an Accept where object is the Edit’s URI, and updates the representation of r that it serves from now on
Here is a specification of object types and the properties they allow to change via Edit.
3.13.1. Edit a comment’s text
Type | Note |
---|---|
Properties | source, content |
Role | None required |
Other requirements | An actor can edit only a Note they’ve authored |
3.13.2. Edit a Ticket’s title and description
Type | Ticket |
---|---|
Properties | summary, source, content |
Role | For the author not required, otherwise triage |
Other requirements | None |
3.13.3. Edit a Factory’s list of available actor types
Type | Factory |
---|---|
Properties | availableActorTypes |
Role | admin |
Other requirements | Each specified type MUST be a type this Factory is programmed to support |
3.14. Repository-PatchTracker Links
3.14.1. Adding
A link between a Repository and a PatchTracker essentially means:
-
The repo officially indicates "send patches via this tracker"
-
The tracker says "I manage patches for this repository"
-
The tracker has access to push commits to the repository (that’s how it merges Merge Requests into the repo)
Given:
-
A Repository R
-
A PatchTracker P
-
An actor with admin access to R, Luke
-
An actor with admin access to P, Aviva
Luke and Aviva can form the link by a direct Grant of the write role for P to access R. See § 3.6.2 Granting access. The process can be initiated via an Invite or Join activity.
Upon successful completion of the process, R SHOULD point to P via the sendPatchesTo property, and P SHOULD point to R via the tracksPatchesFor property.
3.14.2. Removing
Given:
-
A Repository R
-
A PatchTracker P
-
R and P have been linked as described above
-
An actor with admin access to R, Luke
-
An actor with admin access to P, Aviva
Luke or Aviva can remove the link by revoking the write access, see § 3.6.3 Revoking access. Once the Grant is revoked, R and P MUST stop pointing to each another via the sendPatchesTo and tracksPatchesFor properties.
If P has any open Merge Requests for R at the time of revocation, it SHOULD freeze any further edits of these MRs, making them read-only.
4. Actor Interface
This section provides, for each actor types, the various activity types it receives and how it might react to them in order to implement the features described in the § 3 Server to Server Interactions section.
Successful processing SHOULD include inserting the incoming activity to the receiving actor’s inbox & forwarding to the receiving actor’s followers if relevant - for simplicity this step is omitted from some of the behavior dscriptions below
There are links to the Vervis implementation, since it has additional low-level detail and notes that might be useful hints to implementors.
4.1. Person
Vervis implementation: Vervis.Actor.Person
Unlike non-human actors, the Person inbox is also intended for the person to view incoming notifications. Therefore most activity types, even if unrelated specifically to the receiving Person, SHOULD still be inserted into the inbox, for viewing. The interfaces and behaviors described below are specifically the ones where automated action beyond insertion-to-inbox is required.
4.1.1. Accept
Meanings:
-
My follow request has been accepted
-
An invite, for me to become a collaborator on a resource, has been approved by the resource actor
-
My request to create an actor via a Factory has been fulfilled
Processes:
Behavior:
Check the Accept’s object as follows.
-
If it’s a Follow whose object is, or the object’s managing actor is, identical to the Accept’s actor:
-
If it’s an Invite where the object is me:
-
Verify the Accept actor is the resource (i.e. the actor whose collaborators or members URI is the Invite’s target)
-
Insert to my inbox & forward to my followers
-
4.1.2. Follow
Meanings:
-
Someone is asking to follow me
Processes:
Behavior:
-
Verify the object is me
-
If my account settings require manual approval of follow requests, just wait for the human to approve
-
Otherwise, i.e. if no manual approval is required:
4.1.3. Grant
Meanings:
-
A Factory is sending me authorization to use it
-
I’m becoming a collaborator/member in some resource/team
-
A Grant is being extended to me, due to me being a collaborator in some Project or a member of some Team
Processes:
Behavior:
-
If it’s a Factory sending me a write direct-Grant:
-
Insert to my inbox
-
-
If it’s a direct-Grant that fulfills an Invite or Join where I’m the actor being given access, or a Create I’d sent to create that actor:
-
Verify the actor is the resource
-
Verify the given role is identical to what was requested in the Invite or Join, or in the case of Create, verify the role is admin
-
If the resource actor is a Project or Team, send it a delegate-Grant, see § 3.6.2.1 Initial Grant upon resource creation step 1, or § 3.6.2.2 Offering access using Invite activities step 5, or § 3.6.2.3 Requesting access using Join activities option 1 step 4 or option 2 step 5
-
-
If it’s an extension-Grant whose capability is a delegate-Grant I’d sent:
4.1.4. Reject
Meanings:
-
An actor is rejecting my follow request
Processes:
Behavior:
-
Update the status of the follow request in DB
4.1.5. Revoke
Meanings:
-
A direct-Grant given to me is being revoked
-
An extension-Grant given to me is being revoked
Processes:
Behavior:
-
Verify the actor is identical to the actor of the Grant referred by the Revoke’s object
-
Verify that Grant’s target is me
-
Insert to my inbox & update my tracking of that Grant in DB
4.1.6. Undo
Meanings:
-
Someone is asking to unfollow me
Processes:
Behavior:
Check the Undo’s object.
4.2. Factory
Vervis implementation: Vervis.Actor.Factory
4.2.1. Accept
Meanings:
-
A collaborator is being added to me
-
A Team collaborator is being added to me
Processes:
Behavior:
Examine the Accept’s object.
-
If it’s an Invite whose target is my collaborators collection:
-
Verify this collaborator hasn’t been enabled already
-
Enable this collaborator in DB
-
Insert the Accept to my inbox & forward to my followers
-
Send a Grant as described in § 3.6.2.2 Offering access using Invite activities step 3
-
If it’s a Join whose object is my collaborators collection:
-
Verify the Accept is authorized with admin access
-
Verify this collaborator hasn’t been enabled already
-
Enable this collaborator in DB
-
Insert the Accept to my inbox & forward to my followers
-
Send a Grant as described in § 3.6.2.3 Requesting access using Join activities step 2
-
-
If it’s an Add whose target is my teams collection, i.e. a Team Collaborator is being added to me and the process is initiated on our side:
-
Error/ignore, we aren’t supposed get any Accept
-
-
If it’s an Add whose object is me and target points to a collection whose context is a Team that points back to the collection via its teamResources field, i.e. a Team Collaborator is being added to me and the process is initiated on their side:
-
Option 1: If I haven’t yet seen the Team’s Accept: Verify the Accept’s actor is the Team
-
Option 2: If I saw Team’s Acccept but not yet my collaborator’s Accept: Verify the Accept is authorized with admin access
-
Otherwise, error/ignore, no Accept is needed
-
For option 1: Record Team’s Accept in DB
-
For option 2: Record my collaborator’s Accept in DB
-
Insert the Accept to my inbox & forward to my followers
-
For option 2, send an Accept, see § 3.11.1.2 Initiated by the team step 4
-
4.2.2. Add
Meanings:
-
A Team collaborator is being added to me
Processes:
Behavior:
-
If the Add target is my teams list:
-
Verify the Add is authorized with admin access
-
Verify it’s not already an active team of mine
-
Insert the Add to my inbox & forward the Add to my followers
-
Publish an Accept, see § 3.11.1.1 Initiated by the resource step 2
-
If I’m the object, being added to some teams' resource list:
-
Verify the target is a Collection whose context is a Team that points back to the collection via its teamResources field
-
Verify it’s not already an active team of mine
-
Insert the Add to my inbox & forward the Add to my followers
-
4.2.3. Create
Meanings:
-
I’m being requested to spawn a new resource actor
Processes:
Behavior:
-
Verify the Create’s origin is me
-
Verify the Create is authorized with maintain access
-
Launch the new actor described by the Create’s object
-
Insert the Create to my inbox & forward the Create to my followers
-
Publish an Accept, see § 3.12 Creating Resource Actors step 2
4.2.4. Edit
Meanings:
-
My list of available resource actor types is being edited
Processes:
Behavior:
-
Verify the Edit is authorized with admin access
-
Update my list of available types from object’s availableActorTypes
-
Insert the Edit to my inbox & forward the Edit to my followers
-
Send an Accept, see § 3.13 Editing an Object step 2
4.2.5. Follow
Meanings:
-
Someone is asking to follow me
Processes:
Behavior:
-
Verify the object is me
-
Verify the actor isn’t already a follower of me
-
Verify the Follow is authorized with visit access (unless I’m considered a publicly visible resource and then the capability can be omitted)
-
Insert actor to my list of followers
4.2.6. Grant
Meanings:
-
A Team-Collaborator-in-process is sending me the delegate-Grant
Processes:
Behavior:
-
Enable the Team Collaborator in DB
-
Send the Team a start-Grant, see § 3.11.1.3 Delegation step step 1
4.2.7. Invite
Same as Invite handler for the Component actors (TicketTracker, PatchTracker, Repository) and for Project.
Meanings:
-
Someone is inviting someone else to be a collaborator in me
Processes:
Behavior:
-
Verify the target is my collaborators collection
-
Verify the Invite is authorized with admin access
-
Verify the object isn’t already a collaborator of me
-
Insert the Invite to my inbox & forward to followers
Note: The Accept in the last step does NOT indicate that a collaborator has been added. It merely signals to the potential collaborator that the Invite is authorized, and now they can decide whether to accept/reject/ignore it.
4.2.8. Join
Same as Join handler for the Component actors (TicketTracker, PatchTracker, Repository) and for Project.
Meanings:
-
Someone is asking to become a collaborator in me
Processes:
Behavior:
-
Verify the object is my collaborators collection
-
Verify the actor isn’t already a collaborator of me
-
If the Join specifies a capability:
-
Verify the Join is authorized with admin access
-
Insert the Join to my inbox & forward to my followers
-
Publish a Grant, see § 3.6.2.3 Requesting access using Join activities option 1 step 2.2
-
-
Otherwise, i.e. if it doesn’t:
-
Insert the Join to my inbox & forward to my followers
-
4.2.9. Remove
Meanings:
-
One of my Collaborators is being removed
-
One of my Team Collaborators is being removed
Processes:
Behavior:
-
If origin is my collaborators collection:
-
Verify the Remove is authorized with admin access
-
Verify the object is one of my collaborators
-
Remove the object actor from my list of collaborators and invalidate the direct-Grant I had sent them
-
Insert the Remove to my inbox & forward to my followers
-
Publish a Revoke, see § 3.6.3.1 Taking away access using Remove activities step 2.4
-
-
If origin is my teams collection:
-
Verify the Remove is authorized with admin access
-
Verify the object is one of my Team Collaborators
-
Remove the object actor from my list of Team Collaborators and invalidate the start-Grant I had sent it
-
Insert the Remove to my inbox & forward to my followers
-
Publish an Accept, see § 3.11.2.1 Initiated by the resource step 2
-
-
If I’m the object, being removed from the origin specifying the teamResources collection of a Team Collaborator of mine:
-
Nothing to do, just waiting for the Team to send a Revoke on the delegate-Grant it had sent me
-
4.2.10. Revoke
Meanings:
-
A Team Collaborator of mine is revoking the delegate-Grant it gave me
Processes:
Behavior:
-
Verify the actor is a Team Collaborator of mine
-
Verify the object is the delegate-Grant it had sent me
-
Remove the Team from my teams collection and invalidate the start-Grant I had sent it
-
Insert the Revoke to my inbox & forward to my followers
-
Publish an Accept, see § 3.11.2.2 Initiated by the team step 3
4.2.11. Undo
Meanings:
-
Someone is asking to unfollow me
Processes:
Behavior:
4.3. Team
Vervis implementation: Vervis.Actor.Group
4.3.1. Accept
Meanings:
-
Someone is becoming a Collaborator in me
-
I’m gaining access to a resource
-
I’m becoming a child/parent of another Team
-
My child/parent link with another project is being removed
Processes:
Behavior:
Check the Accept’s object as follows.
-
If it’s an Invite whose target is my members collection:
-
Verify this collaborator hasn’t been enabled already
-
Enable this collaborator in DB
-
Insert the Accept to my inbox & forward to my followers
-
Send a Grant as described in § 3.6.2.2 Offering access using Invite activities step 3
-
If it’s a Join whose object is my members collection:
-
Verify the Accept is authorized with admin access
-
Verify this collaborator hasn’t been enabled already
-
Enable this collaborator in DB
-
Insert the Accept to my inbox & forward to my followers
-
Send a Grant as described in § 3.6.2.3 Requesting access using Join activities step 2
-
-
If it’s an Add whose target is my context (i.e. parents) collection, and object is a Team, i.e. I’m getting a new parent team and the process was initiated on our side:
-
Verify I haven’t seen the parent team’ss Accept yet
-
If Accept actor is the parent team:
-
Verify I’ve already published my own Accept
-
Publish a delegate-Grant, see § 3.10.3.2 Initiated by the child step 5
-
-
Otherwise:
-
Just forward to my followers (hopefully this is the parent team’s collaborator giving their approval)
-
-
-
If it’s an Add whose object is me and whose target is the URI of the subteams of some Team, i.e. I’m getting a new parent team and the process was initiated on their side:
-
If I haven’t seen the parent team’s Accept yet:
-
Verify the Accept actor is the parent
-
Insert to my inbox & forward to my followers
-
-
If I’ve already seen the parent team’s Accept, but not yet my collaborator’s Accept:
-
Verify the (new) Accept is authorized with admin access
-
Send a delegate-Grant, see § 3.10.3.1 Initiated by the parent step 4
-
-
-
If it’s an Add whose target is my subteams collection, and object is some Team, i.e. I’m getting a new child and the process was initiated on our side:
-
Ignore/error, I’m not expecting any Accept
-
-
If it’s an Add whose object is me and whose target is the context (i.e. parents) collection of some Team, i.e. I’m getting a new child and the process was initiated on their side:
-
If I haven’t yet seen the child’s Accept:
-
Verify the Accept actor is the child
-
Insert to my inbox & forward to my followers
-
-
If I’ve seen it, but haven’t yet seen my collaborator’s Accept:
-
Verify the Accept is authorized with admin access
-
Send an Accept, see § 3.10.3.2 Initiated by the child step 4
-
-
-
If it’s a Remove whose object is me and whose origin is the URI of the subteams of some Team, i.e. a parent team of mine is being removed and the process was initiated on their side:
-
Verify the actor is the parent
-
Publish a Revoke, see § 3.10.4.2 Initiated by the parent step 3
-
Remove the parent from my context collection
-
Publish a Revoke on every extension-Grant I’ve published as an extension of a Grant I received from the parent, see § 3.10.4.2 Initiated by the parent after step 4
-
-
If it’s an Add whose target is my teamResources collection and object is some resource actor, i.e. I’m becoming a Team Collaborator in a resource and the process was initiated on our side:
-
Verify I haven’t yet seen the resource’s Accept
-
If sender is the resource:
-
Send a delegate-Grant, see § 3.11.1.2 Initiated by the team step 5
-
-
Otherwise:
-
Just forward to my followers
-
-
-
If it’s an Add whose object is me and whose target is some resource actor’s teams collection, i.e. I’m becoming a Team Collaborator in a resource and the process was initiated on their side:
-
If I haven’t seen the resource actor’s Accept yet:
-
Verify actor is the resource
-
Insert to my inbox & forward to my followers
-
-
If I’ve seen it, but not yet my collaborator’s Accept:
-
Verify the (new) Accept is authorized with admin access
-
Send a delegate-Grant, see § 3.11.1.1 Initiated by the resource step 4
-
-
-
If it’s a Remove whose object is me and whose origin is the URI of the teams of some resource actor, i.e. my Team Collaborator access to some resource is being revoked and the process was initiated on their side:
-
Verify the actor is the resource
-
Publish a Revoke, see § 3.11.2.1 Initiated by the resource step 3
-
Remove the resource from my teamResources collection
-
Publish a Revoke on every extension-Grant I’ve published as an extension of a Grant I received from the resource, see § 3.11.2.1 Initiated by the resource after step 3
-
4.3.2. Add
Meanings:
-
I’m gaining access to a resource
-
A child/parent project is being added to me
Processes:
Behavior:
-
If target is my subteams collection, i.e. I’m getting a new child and the process is initiated on our side:
-
Verify the Add is authorized with admin access
-
Verify it’s not already a child or parent of mine
-
Publish an Accept, see § 3.10.3.1 Initiated by the parent step 2
-
If target is my context (i.e. parents) collection, i.e. I’m getting a new parent and the process is initiated on our side:
-
Verify the Add is authorized with admin access
-
Verify it’s not already a child or parent of mine
-
Publish an Accept, see § 3.10.3.2 Initiated by the child step 2
-
If target is my teamResources collection, i.e. I’m becoming a Team Collaborator of some resource and the process is initiated on our side:
-
Verify the object a resource actor that isn’t a Team
-
Verify the Add is authorized with admin access
-
Verify I don’t already have access to this resource
-
Publish an Accept, see § 3.11.1.2 Initiated by the team step 2
-
-
If object is me and target is some Team’s context (i.e. parents) collection, i.e. I’m getting a new child and the process is initiated on their side:
-
Verify I’m not already a child or parent of mine
-
Insert to my inbox & forward to my followers
-
-
If object is me and target is some Team’s subteams collection, i.e. I’m getting a new parent and the process is initiated on their side:
-
Verify I’m not already a child or parent of mine
-
Insert to my inbox & forward to my followers
-
-
If object is me and target is some resource actor’s teams collection, i.e. I’m becoming a Team Collaborator of some resource and the process is initiated on their side:
-
Verify I’m not already a Team Collaborator of this resource
-
Insert to my inbox & forward to my followers
-
4.3.3. Edit
TODO editing team name and description
4.3.4. Follow
Meanings:
-
Someone is asking to follow me
Processes:
Behavior:
-
Verify the object is me
-
Verify the Follow is authorized with visit access (unless I’m considered a publicly visible resource and then the capability can be omitted)
4.3.5. Grant
Meanings:
-
Resource sending me a start-Grant or extension-Grant
-
Member sending me the delegate-Grant
-
Parent team sending me a start-Grant or extension-Grant
-
Almost-child team sending me the delegate-Grant
Processes:
Behavior:
-
Resource sending me a start-Grant or extension-Grant:
-
Verify the Grant is authorized by the delegate-Grant I had sent to the resource
-
Send extension-Grants to each team member and child team of mine, see § 3.6.1.6 Extending a delegation chain
-
-
Member sending me the delegate-Grant:
-
Verify the Grant is authorized by the direct-Grant I had sent to the member
-
Verify I don’t yet have a delegate-Grant from this member
-
For each start-Grant or extension-Grant I received from a parent of resource, send an extension-Grant to the member, see § 3.6.1.6 Extending a delegation chain
-
-
Parent team sending me a start-Grant or extension-Grant:
-
Verify the Grant is authorized by the delegate-Grant I had sent to the parent
-
Send an extension-Grant to every team member and child team, see § 3.6.1.6 Extending a delegation chain
-
-
Almost-child team sending me the delegate-Grant
-
Send a start-Grant and extension-Grants, see § 3.10.3.3 Delegation step
-
4.3.6. Invite
Same as for Factory, see § 4.2.7 Invite. With the exception that target is my members URI rather than collaborators.
4.3.7. Join
Same as for Factory, see § 4.2.8 Join. With the exception that object is my members URI rather than collaborators.
4.3.8. Reject
Same as for TicketTracker, see § 4.6.11 Reject. With the exception that target/object is my members URI rather than collaborators.
4.3.9. Remove
Meanings:
-
One of my members is being removed
-
One of my resources is being removed
-
One of my parents or children is being removed
Processes:
Behavior:
-
If origin is my members collection:
-
Verify the Remove is authorized with admin access
-
Verify the object is one of my members
-
Remove the object actor from my list of members and invalidate the direct-Grant I had sent them
-
Publish a Revoke, see § 3.6.3.1 Taking away access using Remove activities step 2.4
-
Publish Revoke activities on all the extension-Grants I’ve sent to this collaborator
-
-
If origin is my context (i.e. parents) collection:
-
Verify the Remove is authorized with admin access
-
Verify the object is one of my parents
-
Publish an Revoke on the delegate-Grant, see § 3.10.4.1 Initiated by the child step 2
-
Publish Revokes on all extension-Grants I’ve sent, that extend a start-Grant or extension-Grant I’d received from the parent
-
-
If origin is my teamResources collection:
-
Verify the Remove is authorized with admin access
-
Verify the object is in my teamResources collection
-
Remove the object actor from my teamResources collection
-
Publish an Revoke on the delegate-Grant, see § 3.11.2.2 Initiated by the team step 2
-
Publish Revokes on all extension-Grants I’ve sent, that extend a start-Grant or extension-Grant I’d received from the resource
-
-
If I’m the object, being removed from the subteams collection of a parent of mine:
-
Just forward to my followers
-
-
If I’m the object, being removed from the context (i.e. parents) collection of a child of mine:
-
Do nothing, just waiting for child to send a Revoke on the delegate-Grant
-
-
If I’m the object, being removed from the teams collection of one of my resources:
-
Just forward to my followers
-
4.3.10. Undo
Meanings:
-
Someone is asking to unfollow me
Processes:
Behavior:
Check the Undo’s object.
4.4. Project
Vervis implementation: Vervis.Actor.Project
4.4.1. Accept
Meanings:
-
Someone is becoming a Collaborator in me
-
A component is being added to me
-
A Team is becoming a Team Collaborator in me
-
I’m becoming a child/parent of another Project
-
My child/parent link with another project is being removed
Processes:
Behavior:
Check the Accept’s object as follows.
-
If it’s an Invite whose target is my collaborators collection:
-
Verify this collaborator hasn’t been enabled already
-
Enable this collaborator in DB
-
Insert the Accept to my inbox & forward to my followers
-
Send a Grant as described in § 3.6.2.2 Offering access using Invite activities step 3
-
If it’s a Join whose object is my collaborators collection:
-
Verify the Accept is authorized with admin access
-
Verify this collaborator hasn’t been enabled already
-
Enable this collaborator in DB
-
Insert the Accept to my inbox & forward to my followers
-
Send a Grant as described in § 3.6.2.3 Requesting access using Join activities step 2
-
-
If it’s an Add where target is my components collection and object is a component actor, i.e. a component is being added to me and the process was inisiated on our side:
-
If the Accept actor is the component:
-
Insert the component to my components collection
-
Send a delegate-Grant, see § 3.9.3 Adding a component to a project - project side step 5
-
-
If it’s not the component:
-
Just forward the Accept to my followers (hopefully it is the component’s collaborator giving their approval)
-
-
-
If it’s an Add where I’m the object and target is the URI of a collection whose context is a component that points back to the collection via its own context field, i.e. a component is being added to me and the process was initiated on the component’s side:
-
If Accept actor is the component:
-
Verify I haven’t seen the component’s Accept yet
-
Insert to my inbox & forward to my followers
-
-
If it isn’t the component:
-
Verify I’ve seen the component’s Accept
-
Verify the (new) Accept is authorized with admin access
-
Insert the component to my components collection
-
Send a delegate-Grant, see § 3.9.1 Adding a component to a project - component side step 4
-
-
-
If it’s an Add whose target is my subprojects collection, and object is a Project, i.e. I’m getting a new child project and the process was initiated on our side:
-
Verify I haven’t seen the child project’s Accept yet
-
If Accept actor is the child project:
-
Verify I’ve already published my own Accept
-
Publish a delegate-Grant, see § 3.10.1.1 Initiated by the parent step 4
-
-
Otherwise:
-
Just forward to my followers (hopefully this is the child project’s collaborator giving their approval)
-
-
-
If it’s an Add whose object is me and whose target is the URI of the context of some Project, i.e. I’m getting a new child project and the process was initiated on their side:
-
If I haven’t seen the child project’s Accept yet:
-
Verify the Accept actor is the child
-
Insert to my inbox & forward to my followers
-
-
If I’ve already seen the child project’s Accept, but not yet my collaborator’s Accept:
-
Verify the (new) Accept is authorized with admin access
-
Send a delegate-Grant, see § 3.10.1.2 Initiated by the child step 4
-
-
-
If it’s an Add whose target is my context (i.e. parents) collection, and object is some Project, i.e. I’m getting a new parent and the process was initiated on our side:
-
Ignore/error, I’m not expecting any Accept
-
-
If it’s an Add whose object is me and whose target is the subprojects collection of some Project, i.e. I’m getting a new parent and the process was initiated on their side:
-
If I haven’t yet seen the parent’s Accept:
-
Verify the Accept actor is the parent
-
Insert to my inbox & forward to my followers
-
-
If I’ve seen it, but haven’t yet seen my collaborator’s Accept:
-
Verify the Accept is authorized with admin access
-
Send an Accept, see § 3.10.1.1 Initiated by the parent step 4
-
-
-
If it’s a Remove whose object is me and whose origin is the URI of the context of some Project, i.e. a child project of mine is being removed and the process was initiated on their side:
-
Verify the actor is the child
-
Publish a Revoke, see § 3.10.2.1 Initiated by the child step 3
-
Publish a Revoke on every extension-Grant I’ve published as an extension of a Grant I received from the child, see § 3.10.2.1 Initiated by the child step 5
-
4.4.2. Add
Meanings:
-
A Team collaborator is being added to me
-
A component is being added to me
-
A child/parent project is being added to me
Processes:
Behavior:
-
If target is my components collection, i.e. I’m getting a new component and the process is initiated on our side:
-
Verify the Add is authorized with admin access
-
Verify the object is a component actor
-
Verify I don’t yet have this actor as a component
-
Publish an Accept, see § 3.9.3 Adding a component to a project - project side step 2
-
-
If target is my subprojects collection, i.e. I’m getting a new child and the process is initiated on our side:
-
Verify the Add is authorized with admin access
-
Verify it’s not already a child or parent of mine
-
Publish an Accept, see § 3.10.1.1 Initiated by the parent step 2
-
If target is my context (i.e. parents) collection, i.e. I’m getting a new parent and the process is initiated on our side:
-
Verify the Add is authorized with admin access
-
Verify it’s not already a child or parent of mine
-
Publish an Accept, see § 3.10.1.2 Initiated by the child step 2
-
If target is my teams collection, i.e. a Team Collaborator is being added to me and the process is initiated on our side:
-
Verify the Add is authorized with admin access
-
Verify it’s not already an active team of mine
-
Publish an Accept, see § 3.11.1.1 Initiated by the resource step 2
-
If object is me and target is some Project’s context (i.e. parents) collection, i.e. I’m getting a new child and the process is initiated on their side:
-
Verify I’m not already a child or parent of mine
-
Insert to my inbox & forward to my followers
-
-
If object is me and target is some Project’s subprojects collection, i.e. I’m getting a new parent and the process is initiated on their side:
-
Verify I’m not already a child or parent of mine
-
Insert to my inbox & forward to my followers
-
-
If object is me and target is some Team’s teamResources collection, i.e. a Team Collaborator is being added to me and the process is initiated on their side:
-
Verify it’s not already an active team of mine
-
Insert to my inbox & forward to my followers
-
-
If object is me and target is some component actor’s context (i.e. projects) collection, i.e. a component is being added to me and the process is initiated on their side:
-
Verify it’s not already a component of mine
-
Insert to my inbox & forward to my followers
-
4.4.3. Edit
TODO editing project name and description
4.4.4. Follow
Meanings:
-
Someone is asking to follow me
Processes:
Behavior:
-
Verify the object is me
-
Verify the Follow is authorized with visit access (unless I’m considered a publicly visible resource and then the capability can be omitted)
4.4.5. Grant
Meanings:
-
Component sending me the start-Grant
-
Collaborator sending me the delegate-Grant
-
Child project sending me a start-Grant or extension-Grant
-
Almost-parent project sending me the delegate-Grant
-
Almost-team sending me the delegate-Grant
Processes:
Behavior:
-
Component sending me a start-Grant:
-
Verify role is same one specified in the Add
-
Verify the Grant is authorized by the delegate-Grant I had sent to the component
-
Send extension-Grants to each collaborator, team collaborator and parent project of mine, see § 3.6.1.6 Extending a delegation chain
-
-
Collaborator sending me a delegate-Grant:
-
Verify the Grant is authorized by the direct-Grant I had sent to the collaborator
-
Verify I don’t yet have a delegate-Grant from this collaborator
-
Sending extension-Grants to the collaborator, see § 3.6.1.6 Extending a delegation chain:
-
Each start-Grant I received from a component of mine
-
Each start-Grant or extension-Grant I received from a child of mine
-
-
-
Child sending me a start-Grant or extension-Grant:
-
Verify it’s authorized with the delegate-Grant I had sent to the child
-
Send extension-Grants to each collaborator, team collaborator and parent project of mine, see § 3.6.1.6 Extending a delegation chain
-
-
Almost-Parent sending me the delegate-Grant:
-
Send a start-Grant and extension-Grants, see § 3.10.1.3 Delegation step
-
-
Almost-Team-Collaborator sending me the delegate-Grant:
-
Send a start-Grant and extension-Grants, see § 3.10.1.3 Delegation step
-
4.4.6. Invite
Same as for Factory, see § 4.2.7 Invite.
4.4.7. Join
Same as for Factory, see § 4.2.8 Join.
4.4.8. Reject
Same as for TicketTracker, see § 4.6.11 Reject.
4.4.9. Remove
Meanings:
-
One of my Collaborators is being removed
-
One of my Team Collaborators is being removed
-
One of my components is being removed
-
One of my parents or children is being removed
Processes:
Behavior:
-
If origin is my collaborators collection:
-
Verify the Remove is authorized with admin access
-
Verify the object is one of my collaborators
-
Remove the object actor from my list of collaborators and invalidate the direct-Grant I had sent them
-
Publish a Revoke, see § 3.6.3.1 Taking away access using Remove activities step 2.4
-
Publish Revoke activities on all the extension-Grants I’ve sent to this collaborator
-
-
If origin is my components collection:
-
Verify the Remove is authorized with admin access
-
Verify the object is one of my components
-
Remove the object actor from my components collection
-
Publish an Revoke on the delegate-Grant, see § 3.9.4 Removing a component from a project - project side step 2
-
Publish Revokes on all extension-Grants I’ve sent, that extend the start-Grant I’d received from the component
-
-
If origin is my subprojects collection:
-
Verify the Remove is authorized with admin access
-
Verify the object is one of my children
-
Remove the object actor from my subprojects collection
-
Publish an Revoke on the delegate-Grant, see § 3.10.2.2 Initiated by the parent step 2
-
Publish Revokes on all extension-Grants I’ve sent, that extend a start-Grant or extension-Grant I’d received from the child
-
-
If origin is my teams collection:
-
Verify the Remove is authorized with admin access
-
Verify the object is one of my Team Collaborators
-
Remove the object actor from my list of Team Collaborators and invalidate the start-Grant I had sent it
-
Publish an Accept, see § 3.11.2.1 Initiated by the resource step 2
-
-
If I’m the object, being removed from the context (i.e. parents) collection of a child of mine:
-
Just forward to my followers
-
-
If I’m the object, being removed from the subprojects collection of a parent of mine:
-
Do nothing, just waiting for parent to send a Revoke on the delegate-Grant
-
-
If I’m the object, being removed from the context (i.e. projects) collection of a component of mine:
-
Do nothing, just waiting for component to send a Revoke on the start-Grant
-
-
If I’m the object, being removed from the teamResources collection of a Team Collaborator of mine:
-
Nothing to do, just waiting for the Team to send a Revoke on the delegate-Grant it had sent me
-
4.4.10. Undo
Meanings:
-
Someone is asking to unfollow me
Processes:
Behavior:
Check the Undo’s object.
4.5. Repository
Vervis implementation: Vervis.Actor.Repo
4.5.1. Accept
Same as for TicketTracker, see § 4.6.1 Accept.
4.5.2. Add
Same as for TicketTracker, see § 4.6.2 Add.
4.5.3. Edit
TODO edit default branch?
4.5.4. Follow
Meanings:
-
Someone is asking to follow me
Processes:
Behavior:
-
Verify the object is me
-
Verify the Follow is authorized with visit access (unless I’m considered a publicly visible resource and then the capability can be omitted)
4.5.5. Grant
Same as for TicketTracker, see § 4.6.7 Grant.
4.5.6. Invite
Same as for Factory, see § 4.2.7 Invite.
4.5.7. Join
Same as for Factory, see § 4.2.8 Join.
4.5.8. Reject
Same as for TicketTracker, see § 4.6.11 Reject.
4.5.9. Remove
Same as for TicketTracker, see § 4.6.12 Remove.
4.5.10. Undo
Meanings:
-
Someone is asking to unfollow me
Processes:
Behavior:
Check the Undo’s object.
4.6. TicketTracker
Vervis implementation: Vervis.Actor.Deck
4.6.1. Accept
Same as Accept handler for the other Component actors (PatchTracker, Repository).
Meanings:
-
Someone is becoming a Collaborator in me
-
A Team is becoming a Team Collaborator in me
-
I’m becoming a component of a Project
Processes:
Behavior:
Check the Accept’s object as follows.
-
If it’s an Invite whose target is my collaborators collection:
-
Verify this collaborator hasn’t been enabled already
-
Enable this collaborator in DB
-
Insert the Accept to my inbox & forward to my followers
-
Send a Grant as described in § 3.6.2.2 Offering access using Invite activities step 3
-
If it’s a Join whose object is my collaborators collection:
-
Verify the Accept is authorized with admin access
-
Verify this collaborator hasn’t been enabled already
-
Enable this collaborator in DB
-
Insert the Accept to my inbox & forward to my followers
-
Send a Grant as described in § 3.6.2.3 Requesting access using Join activities step 2
-
-
If it’s an Add whose target is my teams collection, i.e. a Team Collaborator is being added to me and the process is initiated on our side:
-
Error/ignore, we aren’t supposed get any Accept
-
-
If it’s an Add whose object is me and target points to a collection whose context is a Team that points back to the collection via its teamResources field, i.e. a Team Collaborator is being added to me and the process is initiated on their side:
-
Option 1: If I haven’t yet seen the Team’s Accept: Verify the Accept’s actor is the Team
-
Option 2: If I saw Team’s Acccept but not yet my collaborator’s Accept: Verify the Accept is authorized with admin access
-
Otherwise, error/ignore, no Accept is needed
-
For option 1: Record Team’s Accept in DB
-
For option 2: Record my collaborator’s Accept in DB
-
Insert the Accept to my inbox & forward to my followers
-
For option 2, send an Accept, see § 3.11.1.2 Initiated by the team step 4
-
-
If it’s an Add whose target is my context (i.e. projects) collection, i.e. I’m being added to a project and the process is initiated on our side:
-
Nothing to do, just ignore the Accept, waiting for the delegate-Grant from the Project
-
-
If it’s an Add whose object is me and target points to a collection whose context is a Project that points back to the collection via its components field, i.e. I’m being added to a project and the process is initiated on their side:
-
If I haven’t yet seen the project’s approval:
-
Verify the author is the project
-
Insert to my inbox & forward to my followers
-
-
If I saw project’s approval, but not my collaborators' approval:
-
Verify the Accept is authorized with admin access
-
Insert to my inbox & forward to my followers
-
Publish an Accept, see § 3.9.3 Adding a component to a project - project side step 4
-
-
If I already saw both approvals, respond with error
-
4.6.2. Add
Same as Accept handler for the other Component actors (PatchTracker, Repository).
Meanings:
-
A Team collaborator is being added to me
-
I’m being added as a component of a Project
Processes:
Behavior:
-
If target is my teams collection, i.e. a Team Collaborator is being added to me and the process is initiated on our side:
-
Verify the Add is authorized with admin access
-
Verify it’s not already an active team of mine
-
Insert the Add to my inbox & forward the Add to my followers
-
Publish an Accept, see § 3.11.1.1 Initiated by the resource step 2
-
If object is me and target points to a collection whose context is a Team that points back to the collection via its teamResources field, i.e. a Team Collaborator is being added to me and the process is initiated on their side:
-
Verify it’s not already an active team of mine
-
Insert to my inbox & forward to my followers
-
-
If target is my context (i.e. projects) collection, i.e. I’m being added to a project and the process is initiated on our side:
-
Verify the Add is authorized with admin access
-
Verify I’m not yet a component of this Project
-
Insert to my inbox & forward to my followers
-
Publish an Accept, see § 3.9.1 Adding a component to a project - component side step 2
-
-
If object is me and target points to a collection whose context is a Project that points back to the collection via its components field, i.e. I’m being added to a project and the process is initiated on their side:
-
Verify I’m not already a component of this Project
-
Insert to my inbox & forward to my followers
-
4.6.3. Create
Meanings:
-
Someone is commenting on a Ticket of mine
Processes:
Behavior:
-
Insert to inbox & forward to my followers & ticket followers
4.6.4. Delete
Meanings:
-
Someone is deleting their comment on a ticket of mine
Processes:
Behavior:
-
Verify sender is the actual author of the Note
-
Insert to inbox & forward to my followers & ticket followers
4.6.5. Edit
Meanings:
-
Someone is deleting their comment on a ticket of mine
-
Someone is asking to edit the text of one of my tickets
Processes:
Behavior:
-
If object is a Note whose context is a Ticket of mine:
-
Verify sender is the actual author of the Note
-
Insert to inbox & forward to my followers & ticket followers
-
4.6.6. Follow
Meanings:
-
Someone is asking to follow me or a Ticket of mine
Processes:
Behavior:
-
Verify the object is me or one of my tickets
-
Verify the Follow is authorized with visit access (unless I’m considered a publicly visible resource and then the capability can be omitted)
4.6.7. Grant
Same as Grant handler for the other Component actors (PatchTracker, Repository).
Meanings:
-
A Project-in-process is sending me the delegate-Grant
-
A Team-Collaborator-in-process is sending me the delegate-Grant
Processes:
Behavior:
Check the Grant’s fulfills field, verify it’s an Add activity that I’ve seen:
-
If it’s a Project-in-process which is now sending me the delegate-Grant, and the previous steps in the process successfully happened:
-
Insert the Project to my list of Projects and enable in DB
-
Send the Project a start-Grant, see § 3.9.1 Adding a component to a project - component side step 5 or § 3.9.3 Adding a component to a project - project side step 6
-
-
If it’s a Team-Collaborator-in-process which is now sending me the delegate-Grant, and the previous steps in the process successfully happened:
-
Insert the Team to my list of Team Collaborators and enable in DB
-
Send the Team a start-Grant, see § 3.11.1.3 Delegation step step 1
-
4.6.8. Invite
Same as for Factory, see § 4.2.7 Invite.
4.6.9. Join
Same as for Factory, see § 4.2.8 Join.
4.6.10. Offer
Meanings:
-
Someone is submitting a new ticket
Processes:
Behavior:
-
Create new Ticket in DB
-
Publish an Accept, see § 3.3.1 Open
4.6.11. Reject
Same as Reject handler for the other Component actors (PatchTracker, Repository).
Meanings:
-
An collaborator Invite is being rejected by the invited actor
-
A collaborator Join request is being rejected by an existing collaborator
Processes:
Behavior:
Check the Reject’s object.
-
If it’s an Invite where target is my collaborators collection:
-
If it’s a Join without a capability and where object is my collaborators collection:
4.6.12. Remove
Same as Remove handler for the other Component actors (PatchTracker, Repository).
Meanings:
-
One of my Collaborators is being removed
-
One of my Team Collaborators is being removed
Processes:
Behavior:
-
If origin is my collaborators collection:
-
Verify the Remove is authorized with admin access
-
Verify the object is one of my collaborators
-
Remove the object actor from my list of collaborators and invalidate the direct-Grant I had sent them
-
Publish a Revoke, see § 3.6.3.1 Taking away access using Remove activities step 2.4
-
-
If origin is my context (i.e. projects) collection:
-
Verify the Remove is authorized with admin access
-
Verify the object is one of the projects in which I’m a component
-
Remove the object actor from my list of projects and invalidate the start-Grant I had sent it
-
Publish an Revoke, see § 3.9.2 Removing a component from a project - component side step 2
-
-
If origin is my teams collection:
-
Verify the Remove is authorized with admin access
-
Verify the object is one of my Team Collaborators
-
Remove the object actor from my list of Team Collaborators and invalidate the start-Grant I had sent it
-
Publish an Accept, see § 3.11.2.1 Initiated by the resource step 2
-
-
If I’m the object, being removed from the origin specifying the components collection of a Project of mine:
-
Just forward to my followers
-
-
If I’m the object, being removed from the origin specifying the teamResources collection of a Team Collaborator of mine:
-
Nothing to do, just waiting for the Team to send a Revoke on the delegate-Grant it had sent me
-
4.6.13. Resolve
Meanings:
-
Someone is requesting to close a ticket
Processes:
Behavior:
-
Verify the object is one of my tickets
-
Verify the Resolve is authorized with triage access
-
Mark the ticket as closed in DB
-
Publish an Accept, see § 3.3.3 Close step 3
4.6.14. Undo
Meanings:
-
Someone is asking to unfollow me
-
Someone is asking to reopen one of my closed tickets
Processes:
Behavior:
Check the Undo’s object.
It’s a Resolve whose object is one of my tickets:
-
Verify the Resolve is authorized with triage access
-
Update the ticket in DB
-
Publish an Accept, see § 3.3.4 Reopen step 3
4.7. PatchTracker
Vervis implementation: Vervis.Actor.Loom
4.7.1. Accept
Same as for TicketTracker, see § 4.6.1 Accept.
4.7.2. Add
Same as for TicketTracker, see § 4.6.2 Add.
4.7.3. Create
Meanings:
-
Someone is commenting on a MR of mine
Processes:
Behavior:
-
Insert to inbox & forward to my followers & MR followers
4.7.4. Delete
Meanings:
-
Someone is deleting their comment on a MR of mine
Processes:
Behavior:
-
Verify sender is the actual author of the Note
-
Insert to inbox & forward to my followers & MR followers
4.7.5. Edit
Meanings:
-
Someone is deleting their comment on a MR of mine
-
Someone is asking to edit the text of one of my MRs
Processes:
Behavior:
-
If object is a Note whose context is a Ticket of mine:
-
Verify sender is the actual author of the Note
-
Insert to inbox & forward to my followers & MR followers
-
4.7.6. Follow
Meanings:
-
Someone is asking to follow me or a MR of mine
Processes:
Behavior:
-
Verify the object is me or one of my tickets
-
Verify the Follow is authorized with visit access (unless I’m considered a publicly visible resource and then the capability can be omitted)
4.7.7. Grant
Same as for TicketTracker, see § 4.6.7 Grant.
4.7.8. Invite
Same as for Factory, see § 4.2.7 Invite.
4.7.9. Join
Same as for Factory, see § 4.2.8 Join.
4.7.10. Offer
Meanings:
-
Someone is submitting a new MR
Processes:
Behavior:
-
Verify the target is me and object is a Ticket with an attachment, see § 3.4.1 Open step 3
-
Create new MR in DB
-
Publish an Accept on the Offer, see § 3.4.1 Open
4.7.11. Reject
Same as for TicketTracker, see § 4.6.11 Reject.
4.7.12. Remove
Same as for TicketTracker, see § 4.6.12 Remove.
4.7.13. Resolve
Meanings:
-
Someone is requesting to close an open MR
Processes:
Behavior:
-
Verify the object is one of my MRs
-
Verify the Resolve is authorized with triage access
-
Mark the MR as closed in DB
-
Publish an Accept, see § 3.3.3 Close step 3
4.7.14. Undo
Meanings:
-
Someone is asking to unfollow me
-
Someone is asking to reopen one of my closed (but not merged) MRs
Processes:
Behavior:
Check the Undo’s object.
It’s a Resolve whose object is one of my closed but not merged MRs:
-
Verify the Resolve is authorized with triage access
-
Update the MR in DB
-
Publish an Accept, see § 3.3.4 Reopen step 3
5. Client to Server Interactions
This section is about how a human or bot can interact with the system by POSTing activities into the outbox of a Person (or Application/Service?) actor, and managing notifications. It’s less urgent than Server-to-Server. fr33 is using C2S in Vervis, and will be gradually working on this part.
ForgeFed uses Activities for client to server interactions, as described by ActivityPub. A client will send objects (eg. a Ticket) wrapped in a Activity (eg. Create) to an actor’s outbox, and in turn the server will take care of delivery.
5.1. Follow Activity
The Follow activity is used to subscribe to the activities of a Repository. The client MUST send a Follow activity to the Person’s outbox. The server in turn delivers the message to the destination inbox.
5.2. Push Activity
The Push activity is used to notify followers when somebody has pushed changes to a Repository. The client MUST send a Push activity to the Repository’s outbox. The server in turn delivers the message to the Repository followers.
6. Actor and Resource Representation
This section is about representation of objects. It’s possible that actor representation will move into a separate section, as well as objects specific to one actor type. And then this section will describe only objects/resources used by multiple actor types, such as comments (person, issue tracker, PR tracker) and tickets (used for both issues and PRs).
6.1. Comment
To represent a comment, e.g. a comment on a ticket or a merge request, use the ActivityPub Note type.
Properties:
[=type=] | Note |
---|---|
[=attributedTo=] | The author of the comment |
[=context=] | The topic of the discussion, e.g. a ticket or a merge request. It MUST be provided. |
[=inReplyTo=] | The entity on which this comment replies. MUST be provided. If the comment is made directly on the discussion topic, then inReplyTo MUST be identical to context. Otherwise, set inReplyTo to the comment to which this comment replies. In that case both comments MUST have an identical context. |
[=content=], [=mediaType=], [=source=] | The comment text, in rendered form and in source form |
{ "@context" : "https://www.w3.org/ns/activitystreams" , "id" : "https://forge.example/luke/comments/rD05r" , "type" : "Note" , "attributedTo" : "https://forge.example/luke" , "context" : "https://dev.example/aviva/game-of-life/merge-requests/19" , "inReplyTo" : "https://dev.example/aviva/comments/E9AGE" , "mediaType" : "text/html" , "content" : "<p>Thank you for the review! I'll submit a correction ASAP</p>" , "source" : { "mediaType" : "text/markdown; variant=Commonmark" , "content" : "Thank you for the review! I'll submit a correction ASAP" }, "published" : "2019-11-06T20:49:05.604488Z" }
6.2. Team Membership
Properties:
[=type=] | Relationship |
---|---|
[=subject=] | A Team |
[=relationship=] | hasMember |
[=object=] | A Person who is a member of the Team
|
[=tag=] | The role that the member has in the team |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://dev.example/teams/mobilizon-dev-team/members/ThmsicTj" , "type" : "Relationship" , "subject" : "https://dev.example/teams/mobilizon-dev-team" , "relationship" : "hasMember" , "object" : "https://dev.example/people/celine" , "tag" : "develop" }
6.3. Team
Properties:
[=type=] | Team |
---|---|
[=name=] | The user-given name of the team, e.g. "Gitea Development Team" |
[=published=] | The time the team was created on the server |
[=summary=] | A one-line user provided description of the project, as HTML, e.g. "We are creating a code hosting platform"
|
[=members=] | Collection of the members of this team |
[=subteams=] | Subteams of this team, i.e. teams whose members (and subteams) inherit the access that this team has been granted (to projects, repositories, etc.) |
[=context=] | Parent Teams of this team, i.e. teams from which this team inherits access to projects, components and resources, e.g. repositories, ticket trackers (and passes them to its members and inherits them to its own subteams) |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://w3id.org/security/v2" , "https://forgefed.org/ns" ], "id" : "https://dev.example/teams/mobilizon-dev-team" , "type" : "Team" , "name" : "Mobilizon Development Team" , "summary" : "We're creating a federated tool for organizing events!" , "members" : { "type" : "Collection" , "totalItems" : 3 , "items" : [ { "type" : "Relationship" , "subject" : "https://dev.example/teams/mobilizon-dev-team" , "relationship" : "hasMember" , "object" : "https://dev.example/people/alice" , "tag" : "admin" }, { "type" : "Relationship" , "subject" : "https://dev.example/teams/mobilizon-dev-team" , "relationship" : "hasMember" , "object" : "https://dev.example/people/bob" , "tag" : "maintain" }, { "type" : "Relationship" , "subject" : "https://dev.example/teams/mobilizon-dev-team" , "relationship" : "hasMember" , "object" : "https://dev.example/people/celine" , "tag" : "develop" } ] }, "subteams" : { "type" : "Collection" , "totalItems" : 2 , "items" : [ "https://dev.example/teams/mobilizon-backend-team" , "https://dev.example/teams/mobilizon-frontend-team" ] }, "context" : "https://dev.example/teams/framasoft-developers" , "publicKey" : { "id" : "https://dev.example/teams/mobilizon-dev-team#main-key" , "owner" : "https://dev.example/teams/mobilizon-dev-team" , "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhki....." }, "inbox" : "https://dev.example/teams/mobilizon-dev-team/inbox" , "outbox" : "https://dev.example/teams/mobilizon-dev-team/outbox" , "followers" : "https://dev.example/teams/mobilizon-dev-team/followers" }
6.4. Project
Properties:
[=type=] | Project |
---|---|
[=name=] | The user-given name of the project, e.g. "My cool project" |
[=published=] | The time the project was created on the server |
[=summary=] | A one-line user provided description of the project, as HTML, e.g.
"<p>A command-line tool that does cool things</p> "
|
[=ticketsTrackedBy=] | The default ticket tracker to use when submitting a ticket to this project (this tracker MUST be listed under the project’s components) |
[=subprojects=] | A Collection of the subprojects of this project |
[=context=] | The parent Project(s) to which this project belongs |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://dev.example/projects/wanderer" , "type" : "Project" , "name" : "Wanderer" , "summary" : "3D nature exploration game" , "components" : { "type" : "Collection" , "totalItems" : 7 , "items" : [ "https://dev.example/repos/opengl-vegetation" , "https://dev.example/repos/opengl-vegetation/patch-tracker" , "https://dev.example/repos/treesim" , "https://dev.example/repos/treesim/patch-tracker" , "https://dev.example/repos/wanderer" , "https://dev.example/repos/wanderer/patch-tracker" , "https://dev.example/issue-trackers/wanderer" ] }, "subprojects" : { "type" : "Collection" , "totalItems" : 2 , "items" : [ "https://dev.example/projects/nature-3d-models" , "https://dev.example/projects/wanderer-fundraising" ] }, "ticketsTrackedBy" : "https://dev.example/issue-trackers/wanderer" , "inbox" : "https://dev.example/projects/wanderer/inbox" , "outbox" : "https://dev.example/projects/wanderer/outbox" , "followers" : "https://dev.example/projects/wanderer/followers" }
6.5. Commit
To represent a named set of changes committed into a repository’s history, use the ForgeFed Commit type. Such a committed change set is called e.g. a commit in Git, and a patch in Darcs.
Properties:
[=type=] | Commit |
---|---|
[=context=] | The Repository that this commit belongs to |
[=attributedTo=] | The commit author; if their actor URI is unknown, it MAY be their email
address as a mailto URI
|
[=created=] | A value of type dateTime (i.e. an ISO 8601 datetime value) specifying the time at which the commit was written by its author |
[=committedBy=] | The entity that committed the commit’s changes into their local copy of the
repo, before the commit was pushed; if their actor URI is unknown, it MAY
be their email address as a mailto URI
|
[=committed=] | The time the commit was committed by its committer |
[=hash=] | The hash identifying the commit, e.g. the commit SHA1 hash in Git; the patch info SHA1 hash in Darcs |
[=summary=] | The commit’s one-line title as HTML-escaped plain text; if the commit title and description are a single commit message string, then the title is the 1st line of the commit message |
[=description=] | A JSON object with a mediaType field and a content field, where mediaType SHOULD be "text/plain" and content is the commit’s
possibly-multi-line description; if the commit title and description are a
single commit message string, then the description is everything after the
1st line of the commit message (possibly with leading whitespace stripped)
|
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://example.dev/alice/myrepo/commits/109ec9a09c7df7fec775d2ba0b9d466e5643ec8c" , "type" : "Commit" , "context" : "https://example.dev/alice/myrepo" , "attributedTo" : "https://example.dev/bob" , "created" : "2019-07-11T12:34:56Z" , "committedBy" : "https://example.dev/alice" , "committed" : "2019-07-26T23:45:01Z" , "hash" : "109ec9a09c7df7fec775d2ba0b9d466e5643ec8c" , "summary" : "Add an installation script, fixes issue #89" , "description" : { "mediaType" : "text/plain" , "content" : "It's about time people can install it on their computers!" } }
6.6. Branch
To represent a repository branch, use the ForgeFed Branch type. It can be a real built-in version control system branch (such as a Git branch) or a copy of the repo used as a branch (e.g. in Darcs, which doesn’t implement branches, and the way to have branches is to keep multiple versions of the repo).
Properties:
[=type=] | Branch |
---|---|
[=context=] | The Repository that this branch belongs to |
[=name=] | The user given name of the branch, e.g. "main" |
[=ref=] | The unique identifier of the branch within the repo, e.g. "refs/heads/main" |
[=team=] | If the branch has its own access/authority/visibility settings, this can be a Collection of the actors who have push/edit access to the branch |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://example.dev/luke/myrepo/branches/master" , "type" : "Branch" , "context" : "https://example.dev/luke/myrepo" , "name" : "master" , "ref" : "refs/heads/master" }
6.7. Repository
To represent a version control repository, use the ForgeFed Repository type.
Properties:
[=type=] | Repository |
---|---|
[=name=] | The user given name of the repository, e.g. "My cool repo" |
[=cloneUri=] | The endpoint from which the content of the repository can be obtained via the native protocol (Git, Hg, etc.) |
[=attributedTo=] | The actor(s) in charge of the repository, e.g. a person or an organization;
if their actor URI is unknown, it MAY be their email address as a mailto URI
|
[=published=] | The time the repository was created on the server |
[=summary=] | A one-line user provided description of the repository, as HTML, e.g.
"<p>A command-line tool that does cool things</p> "
|
[=team=] | Collection of actors who have management/push access to the repository, or the subset of them who is available and wants to be contacted/notified/responsible on repo access related activities/requests |
[=forks=] | OrderedCollection of repositories that are forks of this repository |
[=ticketsTrackedBy=] | The ticket tracker that tracks tickets for this repository, this can be the repository itself if it manages its own tickets |
[=sendPatchesTo=] | The actor that tracks patches for this repository, this can be the repository itself if it manages its own patches and merge requests. For example it may be some external tracker or service, or the user or team to whom the repository belongs. |
[=context=] | The Project(s) to which this repository belongs |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://w3id.org/security/v1" , "https://forgefed.org/ns" ], "id" : "https://dev.example/aviva/treesim" , "cloneUri" : "https://dev.example/aviva/treesim.git" , "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" , "ticketsTrackedBy" : "https://dev.example/aviva/treesim" , "sendPatchesTo" : "https://dev.example/aviva/treesim" , "name" : "Tree Growth 3D Simulation" , "attributedTo" : "https://example.dev/bob" , "summary" : "<p>Tree growth 3D simulator for my nature exploration game</p>" }
6.8. Push
To represent an event of Commits being pushed to a Repository, use a ForgeFed Push activity.
Properties:
[=type=] | Push |
---|---|
[=actor=] | The Repository to which the push was made, and that is publishing this Push activity |
[=attributedTo=] | The entity (person, bot, etc.) that pushed the commits |
[=target=] | The specific repo history tip onto which the commits were added, this is either a Branch (for VCSs that have branches) or a Repository (for VCSs that don’t have branches, only a single history line). If it’s a branch, it MUST be a branch belonging to the repository specified by actor. And if it’s a repository, it MUST be identical to the one specified by actor. |
[=hashBefore=] | Repo/branch/tip hash before adding the new commits |
[=hashAfter=] | Repo/branch/tip hash after adding the new commits |
[=object=] | An OrderedCollection of the Commits being pushed, in reverse chronological order. The items (or orderedItems) property of the collection MUST contain either the whole list of commits being pushed, or a prefix i.e. continuous subset from the beginning of the list (therefore the latest commits). earlyItems MAY be used for listing a suffix i.e. continuous subset from the end (therefore the earliest commits). |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://dev.example/aviva/outbox/E26bE" , "type" : "Push" , "actor" : "https://dev.example/aviva" , "to" : [ "https://dev.example/aviva/followers" , "https://dev.example/aviva/game-of-life" , "https://dev.example/aviva/game-of-life/team" , "https://dev.example/aviva/game-of-life/followers" ], "context" : "https://dev.example/aviva/game-of-life" , "target" : "https://dev.example/aviva/game-of-life/branches/master" , "hashBefore" : "017cbb00bc20d1cae85f46d638684898d095f0ae" , "hashAfter" : "be9f48a341c4bb5cd79ae7ab85fbf0c05d2837bb" , "object" : { "totalItems" : 2 , "type" : "OrderedCollection" , "orderedItems" : [ { "id" : "https://dev.example/aviva/game-of-life/commits/be9f48a341c4bb5cd79ae7ab85fbf0c05d2837bb" , "type" : "Commit" , "attributedTo" : "https://dev.example/aviva" , "context" : "https://dev.example/aviva/game-of-life" , "hash" : "be9f48a341c4bb5cd79ae7ab85fbf0c05d2837bb" , "created" : "2019-12-02T16:07:32Z" , "summary" : "Add widget to alter simulation speed" }, { "id" : "https://dev.example/aviva/game-of-life/commits/fa37fe100a8b1e69933889c5bf3caf95cd3ae1e6" , "type" : "Commit" , "attributedTo" : "https://dev.example/aviva" , "context" : "https://dev.example/aviva/game-of-life" , "hash" : "fa37fe100a8b1e69933889c5bf3caf95cd3ae1e6" , "created" : "2019-12-02T15:51:52Z" , "summary" : "Set window title correctly, fixes issue #7" } ] } }
6.9. Ticket
To represent a work item in a project, use the ForgeFed Ticket type.
TODO decide on ticket categories/subtypes and update below
TODO decide on property for titles, update below
TODO properly document history
or remove it from example
Properties:
[=type=] | Ticket |
---|---|
[=context=] | The TicketTracker or PatchTracker to which this ticket belongs |
[=attributedTo=] | The actor (person, bot, etc.) who submitted the ticket |
[=summary=] | The ticket’s one-line title, as HTML-escaped plain text |
[=content=], [=mediaType=] | The ticket’s (possibly multi-line) detailed description text, in rendered form |
[=source=] | Source form of the ticket’s description |
[=published=] | The time the ticket submission was accepted (which may not be the same as the time the ticket was submitted) |
[=followers=] | Collection of the followers of the ticket, actors who want to be notified on activity related to the ticket |
[=team=] | Collection of project team members who have responsibility for work on this ticket and want to be notified on activities related to it |
[=replies=] | Collection of direct comments made on the ticket (but not comments made on other comments on the ticket) |
[=dependants=] | Collection of Tickets which depend on this ticket |
[=dependencies=] | Collection of Tickets on which this ticket depends |
[=isResolved=] | Whether the work on this ticket is done |
[=resolvedBy=] | If the work on this ticket is done, who marked the ticket as resolved, or which activity did so |
[=resolved=] | When the ticket has been marked as resolved |
There’s an important distinction between these two kinds of tickets:
-
Task: A work item which tracks some task to be done, in which the task and its results are described in text, but the work itself is done elsewhere. This is often called "issue" in software project hosting platforms. Tasks are general-purpose work items that aren’t specific to software development or software projects.
-
Merge request: A work item that includes a proposal or request to apply some specific changes to a specific Repository. The work requested by the work item is to review and (decide whether to) merge the proposed patches to the repository. This kind of work item is often called "Pull Request" or "Merge Request" on software project hosting platforms.
6.9.1. Task / Issue
A task is represented as a § 6.9 Ticket as described above, with the following additional requirements:
-
context is the TicketTracker to which this task belongs
-
There is no attachment of type Offer (but there may be attachment of other types)
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://dev.example/aviva/game-of-life/issues/107" , "type" : "Ticket" , "context" : "https://dev.example/aviva/game-of-life" , "attributedTo" : "https://forge.example/luke" , "summary" : "Window title is empty" , "content" : "<p>When I start the simulation, window title disappears suddenly</p>" , "mediaType" : "text/html" , "source" : { "mediaType" : "text/markdown; variant=Commonmark" , "content" : "When I start the simulation, window title disappears suddenly" , }, "published" : "2019-11-04T07:00:04.465807Z" , "followers" : "https://dev.example/aviva/game-of-life/issues/107/followers" , "team" : "https://dev.example/aviva/game-of-life/issues/107/team" , "replies" : "https://dev.example/aviva/game-of-life/issues/107/discussion" , "history" : "https://dev.example/aviva/game-of-life/issues/107/activity" , "dependants" : "https://dev.example/aviva/game-of-life/issues/107/rdeps" , "dependencies" : "https://dev.example/aviva/game-of-life/issues/107/deps" , "isResolved" : true , "resolvedBy" : "https://code.example/martin" , "resolved" : "2020-02-07T06:45:03.281314Z" }
6.9.2. Merge Request / Pull Request
A merge request is represented as a § 6.9 Ticket as described above, with the following additional requirements:
-
context is the PatchTracker to which this merge request belongs
-
There is no attachment of type Offer (but there may be attachment of other types)
-
There is exactly one attachment of type Offer, as described below
-
There MAY be more attachments, but they MUST NOT be of type Offer
In that special attachment of type Offer:
-
origin is the Repository or Branch from which the proposed changes are proposed to be merged into the target repository/branch
-
target is the Repository or Branch into which the changes are proposed to be merged
-
object is an OrderedCollection of Patches in reverse chronological order, in which, in addition to standard OrderedCollection properties:
-
context is (the id of) the § 6.9 Ticket
-
previousVersions is a list of previous versions of the merge request’s proposed changes, i.e. previous versions of this OrderedCollection; each of those uses currentVersion to point back to this latest version
-
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://dev.example/aviva/game-of-life/pulls/825" , "type" : "Ticket" , "context" : "https://dev.example/aviva/game-of-life" , "attributedTo" : "https://forge.example/luke" , "summary" : "Fix the empty window title bug" , "content" : "<p>This fixes the bug making the title disappear</p>" , "mediaType" : "text/html" , "source" : { "mediaType" : "text/markdown; variant=Commonmark" , "content" : "This fixes the bug making the title disappear" , }, "published" : "2022-09-15T14:52:00.125987Z" , "followers" : "https://dev.example/aviva/game-of-life/pulls/825/followers" , "replies" : "https://dev.example/aviva/game-of-life/pulls/825/discussion" , "isResolved" : false , "attachment" : { "type" : "Offer" , "origin" : { "type" : "Branch" , "context" : "https://forge.example/luke/game-of-life" , "ref" : "refs/heads/fix-title-bug" }, "target" : { "type" : "Branch" , "context" : "https://dev.example/aviva/game-of-life" , "ref" : "refs/heads/main" }, "object" : { "id" : "https://dev.example/aviva/game-of-life/pulls/825/versions/1" , "type" : "OrderedCollection" , "totalItems" : 1 , "items" : [ { "type" : "Patch" , "attributedTo" : "https://forge.example/luke" , "context" : "https://dev.example/aviva/game-of-life/pulls/825/versions/1" , "mediaType" : "application/x-git-patch" , "content" : "From c9ae5f4ff4a330b6e1196ceb7db1665bd4c1..." } ], "context" : "https://dev.example/aviva/game-of-life/pulls/825" } } }
6.10. Patch
[=type=] | Patch |
---|---|
[=attributedTo=] | The Person who has written the patch |
[=context=] | An OrderedCollection representing a sequence of patches, being submitted together as a proposed change to a certain Repository, and this patch is an item in that collection |
[=content=] | A description of the changes that this patch proposes, encoded in the format specified by mediaType |
[=mediaType=] | A native patch format used by the Version Control System of the Repository to which the patch is proposed, and in which the content of this patch is encoded |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://dev.example/aviva/game-of-life/pulls/825/versions/1/patches/1" , "type" : "Patch" , "attributedTo" : "https://forge.example/luke" , "context" : "https://dev.example/aviva/game-of-life/pulls/825/versions/1" , "mediaType" : "application/x-git-patch" , "content" : "From c9ae5f4ff4a330b6e1196ceb7db1665bd4c1..." }
6.11. Factory
Properties:
[=type=] | Factory |
---|---|
[=name=] | The user-given name of the factory, e.g. "My default factory" |
[=published=] | The time the project was created on the server |
[=summary=] | A one-line user provided description of the factory, as HTML, e.g.
"<p>Allows local users to create public resources</p> "
|
[=availableActorTypes=] | Zero or more resource actor types whose creatio is supported and enabled by this Factory. |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://w3id.org/security/v2" , "https://forgefed.org/ns" ], "id" : "https://grape.fr33domlover.site/factories/YGQoZ" , "type" : "Factory" , "name" : "final-factory" , "summary" : "." , "availableActorTypes" : [ "TicketTracker" , "Project" , "Team" , "Repository" ], "outbox" : "https://grape.fr33domlover.site/factories/YGQoZ/outbox" , "publicKey" : [ "https://grape.fr33domlover.site/akey1" , "https://grape.fr33domlover.site/akey2" ], "collaborators" : "https://grape.fr33domlover.site/factories/YGQoZ/collabs" , "followers" : "https://grape.fr33domlover.site/factories/YGQoZ/followers" , "inbox" : "https://grape.fr33domlover.site/factories/YGQoZ/inbox" , "teams" : "https://grape.fr33domlover.site/factories/YGQoZ/teams" }
7. Access Control
7.1. Giving Access
7.1.1. Invite
To offer some actor access to a shared resource (such as a repository or a ticket tracker), use an ActivityPub Invite activity.
Properties:
[=type=] | Invite |
---|---|
[=actor=] | The entity (person, bot, etc.) that is offering access |
[=instrument=] | A Role specifying which operations on the resource are being allowed |
[=target=] | The resource, access to which is being given (for example, a repository) |
[=object=] | The actor who is being gives access to the resource |
[=capability=] | A previously published Grant , giving the actor permission to invite
more actors to access the resource
|
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://dev.example/aviva/outbox/B47d3" , "type" : "Invite" , "actor" : "https://dev.example/aviva" , "to" : [ "https://dev.example/aviva/followers" , "https://coding.community/repos/game-of-life" , "https://coding.community/repos/game-of-life/followers" , "https://software.site/bob" , "https://software.site/bob/followers" ], "instrument" : "maintain" , "target" : "https://coding.community/repos/game-of-life" , "object" : "https://software.site/bob" , "capability" : "https://coding.community/repos/game-of-life/outbox/2c53A" }
7.1.2. Join
To request access to a shared resource, use an ActivityPub Join activity.
Properties:
[=type=] | Join |
---|---|
[=actor=] | The entity (person, bot, etc.) that is requesting access |
[=instrument=] | A Role specifying which operations on the resource are being requested |
[=object=] | The resource, access to which is being given (for example, a repository) |
[=capability=] | (optional) A previously published Grant , giving the actor permission
to gain access to the resource without the approval of another actor. If capability isn’t provided, the resource won’t grant access before someone
with adequate access approves the Join request.
|
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://software.site/bob/outbox/c97E3" , "type" : "Join" , "actor" : "https://software.site/bob" , "to" : [ "https://coding.community/repos/game-of-life" , "https://coding.community/repos/game-of-life/followers" , "https://software.site/bob/followers" ], "instrument" : "maintain" , "object" : "https://coding.community/repos/game-of-life" , "capability" : "https://coding.community/repos/game-of-life/outbox/d38Fa" }
7.1.3. Grant
To give some actor access to a shared resource, use a ForgeFed Grant activity.
Properties:
[=type=] | Grant |
---|---|
[=actor=] | The entity (person, bot, etc.) that is giving access |
[=object=] | A Role specifying which operations on the resource are being allowed |
[=context=] | The resource, access to which is being given (for example, a repository) |
[=target=] | The actor who is being gives access to the resource |
[=fulfills=] | The activity that triggered the sending of the Grant , such as a related Invite (another example: if Alice Creates a new repository, the
repository may automatically send back a Grant giving Alice admin
access, and this Grant’s fulfills refers to the Create that Alice
sent)
|
[=result=] | A URI that can be used later for verifying that the given access is still
approved, thus allowing the actor granting the access to revoke it.
Alternatively, a JSON object where id is the URI and duration MAY
be specified to allow to skip the revocation check if the duration time
hasn’t yet passed since the last check. If duration is specified, it
MUST be positive, and specify only an integral number of seconds that is
less than 2^63 , and no other component.
|
[=allows=] | Modes of invocation and/or delegation that this Grant is meant to be used
for
|
[=delegates=] | If this Grant is a delegation, i.e. it is passing on some access that it
has received, delegates specifies the parent Grant that it has received
and now passing on
|
[=startTime=] | (optional) The time at which the Grant becomes valid |
[=endTime=] | (recommended) The time at which the Grant expires |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://coding.community/repos/game-of-life/outbox/9fA8c" , "type" : "Grant" , "actor" : "https://coding.community/repos/game-of-life" , "to" : [ "https://dev.example/aviva" , "https://dev.example/aviva/followers" , "https://coding.community/repos/game-of-life/followers" , "https://software.site/bob" , "https://software.site/bob/followers" ], "object" : "maintain" , "context" : "https://coding.community/repos/game-of-life" , "target" : "https://software.site/bob" , "fulfills" : "https://dev.example/aviva/outbox/B47d3" , "allows" : "invoke" , "endTime" : "2023-12-31T23:00:00-08:00" }
7.2. Canceling Access
7.2.1. Remove
To disable an actor’s membership in a shared resource, invalidating their access to it, use an ActivityPub Remove activity.
Properties:
[=type=] | Remove |
---|---|
[=actor=] | The actor (person, bot, etc.) that is disabling access disabled |
[=object=] | The actor whose access to the resource is being taken away |
[=origin=] | The resource, access to which is being taken away (for example, a repository) |
[=capability=] | A previously published Grant , giving the actor permission to disable
the object actor’s access to the resource
|
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://dev.example/aviva/outbox/F941b" , "type" : "Remove" , "actor" : "https://dev.example/aviva" , "to" : [ "https://dev.example/aviva/followers" , "https://coding.community/repos/game-of-life" , "https://coding.community/repos/game-of-life/followers" , "https://software.site/bob" , "https://software.site/bob/followers" ], "origin" : "https://coding.community/repos/game-of-life" , "object" : "https://software.site/bob" , "capability" : "https://coding.community/repos/game-of-life/outbox/2c53A" }
7.2.2. Leave
To withdraw your consent for membership in a shared resource, invalidating your access to it, use an ActivityPub Leave activity.
Properties:
[=type=] | Leave |
---|---|
[=actor=] | The actor (person, bot, etc.) that is requesting to disable their own access |
[=object=] | The resource, access to which is being disabled (for example, a repository) |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://software.site/bob/outbox/d08F4" , "type" : "Leave" , "actor" : "https://software.site/bob" , "to" : [ "https://coding.community/repos/game-of-life" , "https://coding.community/repos/game-of-life/followers" , "https://software.site/bob/followers" ], "object" : "https://coding.community/repos/game-of-life" }
7.2.3. Revoke
Another activity that can be used for disabling access is Revoke.
While § 7.2.1 Remove and § 7.2.2 Leave are meant for undoing the effects
of § 7.1.1 Invite and § 7.1.2 Join, Revoke
is provided as an opposite of § 7.1.3 Grant. See the Behavior specification for more information about the
usage of these different activity types in revocation of access to shared
resources.
Properties:
[=type=] | Revoke |
---|---|
[=actor=] | The actor (person, bot, etc.) that is revoking access |
[=fulfills=] | An activity that triggered the sending of the Revoke , such as a related Remove or Leave
|
[=object=] | specific § 7.1.3 Grant activities being undone, i.e. the access that they granted is now disabled and it cannot be used anymore as the capability of activities. Each Grant may either be mentioned by its id URI, or be included as a full object that includes an integrity proof. |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://coding.community/repos/game-of-life/outbox/1C0e2" , "type" : "Revoke" , "actor" : "https://coding.community/repos/game-of-life" , "to" : [ "https://coding.community/repos/game-of-life/followers" , "https://software.site/bob" , "https://software.site/bob/followers" ], "object" : "https://coding.community/repos/game-of-life/outbox/9fA8c" }
7.2.4. Undo a Grant
The Behavior spec describes flows in which the § 7.2.3 Revoke activity is used by resources (more accurately, by the actors managing them) to announce that they’re disabling § 7.1.3 Grants that they previously sent. To allow for a clear distinction, another activity is provided here, for other actors to request the revocation of specific § 7.1.3 Grants: The ActivityPub Undo activity.
It’s likely that Grant
s would exist behind-the-scenes in applications, and
human actors would then use activities such as Remove
and Leave
for
disabling access. But the ability to disable specific Grant
s may be required
for ensuring and maintaining system security, therefore Undo
is provided here
as well.
Properties:
[=type=] | Undo |
---|---|
[=actor=] | The actor (person, bot, etc.) that is revoking access |
[=object=] | specific § 7.1.3 Grant activities being undone, i.e. the access that they granted is now disabled and it cannot be used anymore as the capability of activities |
[=capability=] | A previously published Grant , giving the actor permission to disable
the object actor’s access to the resource
|
8. Vocabulary
8.1. Types
The base URI of all ForgeFed terms is https://forgefed.org/ns#
.
The ForgeFed vocabulary has a JSON-LD context whose URI is https://forgefed.org/ns
. Implementers MUST either include the
ActivityPub and ForgeFed contexts in their object definitions, or other
contexts that would result with the ActivityPub and ForgeFed terms being
assigned they correct full URIs. Implementers MAY include additional contexts
and terms as appropriate.
A typical @context
of a ForgeFed object may look like this:
8.1.1. Activities
8.1.1.1. General
Name | Edit |
---|---|
URI | https://forgefed.org/ns#Edit |
Extends | Activity |
Description | Indicates that actor is editing or asking to edit the object specified by object. In that object, id MUST be specified, and every other field is a field being set to a new value. |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "http://dev.example/people/JABld/outbox/AZ01d" , "actor" : "http://dev.example/people/JABld" , "type" : "Edit" , "object" : { "id" : "http://dev.example/people/JABld/messages/PAQlD" , "source" : "Hello world" , "content" : "<p>Hello world</p>" }, "to" : [ "http://dev.example/decks/ld6zd" , "http://dev.example/people/JABld/followers" , "http://dev.example/decks/ld6zd/followers" , "http://dev.example/decks/ld6zd/tickets/kd9ed/followers" ] }
8.1.1.2. Related to access control
Name | Grant |
---|---|
URI | https://forgefed.org/ns#Grant |
Extends | Activity |
Description | Indicates that target is being given (by the actor) access to a resource specified by context under the role/permission specified by object. |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://example.dev/aviva/outbox/reBGo" , "type" : "Grant" , "actor" : "https://example.dev/aviva" , "to" : [ "https://example.dev/aviva/followers" , "https://example.dev/aviva/myproject" , "https://example.dev/aviva/myproject/followers" , "https://example.dev/bob" , "https://example.dev/bob/followers" ], "object" : "write" , "context" : "https://example.dev/aviva/myproject" , "target" : "https://example.dev/bob" }
Name | Revoke |
---|---|
URI | https://forgefed.org/ns#Revoke |
Extends | Activity |
Description | Indicates that the actor is canceling target’s access to a resource specified by context under the role specified by instrument, making the Grant activities specified by object unusable anymore in other activities' capability field. |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://example.dev/myproject/outbox/nlTxb" , "type" : "Revoke" , "actor" : "https://example.dev/myproject" , "to" : [ "https://example.dev/myproject/followers" , "https://example.dev/users/aviva" ], "object" : "https://example.dev/myproject/outbox/reBGo" , "instrument" : "https://example.dev/roles/developer" , "context" : "https://example.dev/myproject" , "target" : "https://example.dev/users/aviva" }
8.1.1.3. Related to repositories
Name | Push |
---|---|
URI | https://forgefed.org/ns#Push |
Extends | Activity |
Description | Indicates that new content has been pushed to the Repository. |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://example.dev/aviva/myproject/outbox/reBGo" , "type" : "Push" , "actor" : "https://example.dev/aviva/myproject" , "attributedTo" : "https://example.dev/aviva" , "to" : [ "https://example.dev/aviva" , "https://example.dev/aviva/followers" , "https://example.dev/aviva/myproject/followers" ], "summary" : "<p>Aviva pushed a commit to myproject</p>" , "object" : { "type" : "OrderedCollection" , "totalItems" : 1 , "items" : [ { "id" : "https://example.dev/aviva/myproject/commits/d96596230322716bd6f87a232a648ca9822a1c20" , "type" : "Commit" , "attributedTo" : "https://example.dev/aviva" , "context" : "https://example.dev/aviva/myproject" , "hash" : "d96596230322716bd6f87a232a648ca9822a1c20" , "created" : "2019-11-03T13:43:59Z" , "summary" : "Provide hints in sign-up form fields" , } ] }, "target" : "https://example.dev/aviva/myproject/branches/master" }
Name | Apply |
---|---|
URI | https://forgefed.org/ns#Apply |
Extends | Activity |
Description | Indicates a request to apply a Merge Request to a Repository. |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://fig.fr33domlover.site/people/qn870/outbox/ZnqL0" , "type" : "Apply" , "actor" : "https://fig.fr33domlover.site/people/qn870" , "object" : "https://fig.fr33domlover.site/looms/9nOkn/cloths/mbWob/bundles/mbWob" , "target" : { "type" : "Branch" , "context" : "https://fig.fr33domlover.site/repos/9nOkn" , "name" : "main" , "ref" : "/refs/heads/main" }, "capability" : "https://fig.fr33domlover.site/looms/9nOkn/outbox/kDJx0" , "to" : [ "https://fig.fr33domlover.site/looms/9nOkn" , "https://fig.fr33domlover.site/people/qn870/followers" , "https://fig.fr33domlover.site/looms/9nOkn/followers" , "https://fig.fr33domlover.site/looms/9nOkn/cloths/mbWob/followers" ] }
8.1.1.4. Related to ticket tracking
Name | Resolve |
---|---|
URI | https://forgefed.org/ns#Resolve |
Extends | Activity |
Description | Indicates that a Ticket is being closed. |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://grape.fr33domlover.site/people/WZpnG/outbox/GQvnR" , "type" : "Resolve" , "actor" : "https://grape.fr33domlover.site/people/WZpnG" , "object" : "https://fig.fr33domlover.site/decks/W058b/tickets/3bPVn" , "capability" : "https://grape.fr33domlover.site/groups/OZLdZ/outbox/ZLdDZ" , "to" : [ "https://grape.fr33domlover.site/people/WZpnG/followers" , "https://fig.fr33domlover.site/decks/W058b" , "https://fig.fr33domlover.site/decks/W058b/followers" , "https://fig.fr33domlover.site/decks/W058b/tickets/3bPVn/followers" ], "proof" : { "created" : "2024-07-09T07:02:45.038760903Z" , "cryptosuite" : "jcs-eddsa-2022" , "proofPurpose" : "assertionMethod" , "proofValue" : "z4yiaWtjPeUjBvoXpHffjguVd8uHsSfYr4zxxFJbZwPVLtRNCk3uMKtnC3nRZ8vRM3h36B6VLrFagVerxcymhj2NP" , "type" : "DataIntegrityProof" , "verificationMethod" : "https://grape.fr33domlover.site/akey1" } }
8.1.2. Actors
8.1.2.1. Software development components
Name | Repository |
---|---|
URI | https://forgefed.org/ns#Repository |
Extends | Object |
Description | Represents a version control system repository. |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://w3id.org/security/v1" , "https://forgefed.org/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>" }
Name | TicketTracker |
---|---|
URI | https://forgefed.org/ns#TicketTracker |
Extends | Object |
Description | Represents a ticket tracker, i.e. a project managing a list of work items. |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://w3id.org/security/v2" , "https://forgefed.org/ns" ], "id" : "https://dev.example/aviva/treesim" , "type" : [ "Repository" , "TicketTracker" ], "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" , "name" : "Tree Growth 3D Simulation" , "summary" : "<p>Tree growth 3D simulator for my nature exploration game</p>" }
Name | PatchTracker |
---|---|
URI | https://forgefed.org/ns#PatchTracker |
Extends | Object |
Description | Represents a tracker of merge requests, i.e. a project managing a list of patches or branches submitted as proposed changes to a given Repository. |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://w3id.org/security/v2" , "https://forgefed.org/ns" ], "id" : "https://dev.example/aviva/treesim" , "type" : [ "Repository" , "TicketTracker" , "PatchTracker" ], "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" , "name" : "Tree Growth 3D Simulation" , "summary" : "<p>Tree growth 3D simulator for my nature exploration game</p>" }
8.1.2.2. Organizational structure tools
Name | Project |
---|---|
URI | https://forgefed.org/ns#Project |
Extends | Object |
Description | Represents a project, a planned endeavor that involves usage of tools related to the software development lifecycle. It may be a software project, but may also be totally unrelated to software development. For example, it may be a book that is being written using Markdown files kept in a Git repository. A Project object is a way to collect forge related components together under one title. |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://w3id.org/security/v2" , "https://forgefed.org/ns" ], "id" : "https://dev.example/projects/wanderer" , "type" : "Project" , "name" : "Wanderer" , "summary" : "3D nature exploration game" , "components" : { "type" : "Collection" , "totalItems" : 7 , "items" : [ "https://dev.example/repos/opengl-vegetation" , "https://dev.example/repos/opengl-vegetation/patch-tracker" , "https://dev.example/repos/treesim" , "https://dev.example/repos/treesim/patch-tracker" , "https://dev.example/repos/wanderer" , "https://dev.example/repos/wanderer/patch-tracker" , "https://dev.example/issue-trackers/wanderer" ] }, "publicKey" : { "id" : "https://dev.example/projects/wanderer#main-key" , "owner" : "https://dev.example/projects/wanderer" , "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhki....." }, "inbox" : "https://dev.example/projects/wanderer/inbox" , "outbox" : "https://dev.example/projects/wanderer/outbox" , "followers" : "https://dev.example/projects/wanderer/followers" }
Name | Team |
---|---|
URI | https://forgefed.org/ns#Team |
Extends | Object |
Description | Represents a group of people working together, collaborating on shared resources. Each member Person in the team has a defined role, affecting the level of access they have to the team’s shared resources and to managing the team itself. |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://w3id.org/security/v2" , "https://forgefed.org/ns" ], "id" : "https://dev.example/teams/mobilizon-dev-team" , "type" : "Team" , "name" : "Mobilizon Development Team" , "summary" : "We're creating a federated tool for organizing events!" , "members" : { "type" : "Collection" , "totalItems" : 3 , "items" : [ { "type" : "Relationship" , "subject" : "https://dev.example/teams/mobilizon-dev-team" , "relationship" : "hasMember" , "object" : "https://dev.example/people/alice" , "tag" : "https://roles.example/admin" }, { "type" : "Relationship" , "subject" : "https://dev.example/teams/mobilizon-dev-team" , "relationship" : "hasMember" , "object" : "https://dev.example/people/bob" , "tag" : "maintain" }, { "type" : "Relationship" , "subject" : "https://dev.example/teams/mobilizon-dev-team" , "relationship" : "hasMember" , "object" : "https://dev.example/people/celine" , "tag" : "develop" } ] }, "subteams" : { "type" : "Collection" , "totalItems" : 2 , "items" : [ "https://dev.example/teams/mobilizon-backend-team" , "https://dev.example/teams/mobilizon-frontend-team" ] }, "context" : "https://dev.example/teams/framasoft-developers" , "publicKey" : { "id" : "https://dev.example/teams/mobilizon-dev-team#main-key" , "owner" : "https://dev.example/teams/mobilizon-dev-team" , "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhki....." }, "inbox" : "https://dev.example/teams/mobilizon-dev-team/inbox" , "outbox" : "https://dev.example/teams/mobilizon-dev-team/outbox" , "followers" : "https://dev.example/teams/mobilizon-dev-team/followers" }
8.1.2.3. Utility
Name | Factory |
---|---|
URI | https://forgefed.org/ns#Factory |
Extends | Object |
Description | A service actor that creates resource actors (such as Repository), exists to allow access control on creation of remote resources. |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://w3id.org/security/v2" , "https://forgefed.org/ns" ], "id" : "https://grape.fr33domlover.site/factories/YGQoZ" , "type" : "Factory" , "name" : "final-factory" , "summary" : "." , "availableActorTypes" : [ "TicketTracker" , "Project" , "Team" , "Repository" ], "outbox" : "https://grape.fr33domlover.site/factories/YGQoZ/outbox" , "publicKey" : [ "https://grape.fr33domlover.site/akey1" , "https://grape.fr33domlover.site/akey2" ], "collaborators" : "https://grape.fr33domlover.site/factories/YGQoZ/collabs" , "followers" : "https://grape.fr33domlover.site/factories/YGQoZ/followers" , "inbox" : "https://grape.fr33domlover.site/factories/YGQoZ/inbox" , "teams" : "https://grape.fr33domlover.site/factories/YGQoZ/teams" }
8.1.3. Objects
Name | CapabilityUsage |
---|---|
URI | https://forgefed.org/ns#CapabilityUsage |
Extends | Object |
Values | This specification defines 3: gatherAndConvey, distribute and invoke |
Description | Represents a mode of using a Grant as an Object Capability (OCAP).
There are two conceptual operations for Grant s: Invocation (acting
on the resource under the specified role) and Delegation (passing on the
access to more actors, possibly with reduced privileges). A value of this
type refers to one or both of these operations, and possibly to more
specific conditions and restrictions on applying them.
|
Name | Role |
---|---|
URI | https://forgefed.org/ns#Role |
Extends | Object |
Values | visit, report, triage, write, maintain, admin, delegate |
Description | Represents a role that an actor has within a Team, or a role defining the level of access an actor has to a resource. |
Name | Branch |
---|---|
URI | https://forgefed.org/ns#Branch |
Extends | Object |
Description | Represents a named variable reference to a version of the Repository, typically used for committing changes in parallel to other development, and usually eventually merging the changes into the main history line. |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://example.dev/luke/myrepo/branches/master" , "type" : "Branch" , "name" : "master" , "context" : "https://example.dev/luke/myrepo" , "ref" : "refs/heads/master" }
Name | Commit |
---|---|
URI | https://forgefed.org/ns#Commit |
Extends | Object |
Description | Represents a named set of changes in the history of a Repository. This
is called "commit" in Git, Mercurial and Monotone; "patch" in Darcs;
sometimes called "change set". Note that Commit is a set of changes that
already exists in a repo’s history, while a Patch is a separate
proposed change set, that could be applied and pushed to a repo,
resulting with a Commit .
|
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://example.dev/alice/myrepo/commits/109ec9a09c7df7fec775d2ba0b9d466e5643ec8c" , "type" : "Commit" , "context" : "https://example.dev/alice/myrepo" , "attributedTo" : "https://example.dev/bob" , "committedBy" : "https://example.dev/alice" , "hash" : "109ec9a09c7df7fec775d2ba0b9d466e5643ec8c" , "summary" : "Add an installation script, fixes issue #89" , "description" : { "mediaType" : "text/plain" , "content" : "It's about time people can install on their computers!" }, "created" : "2019-07-11T12:34:56Z" , "committed" : "2019-07-26T23:45:01Z" }
Name | Patch |
---|---|
URI | https://forgefed.org/ns#Patch |
Extends | Object |
Description | Represents a named set of changes that are being proposed for applying to a specific Repository. |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://dev.example/aviva/game-of-life/pulls/825/versions/1/patches/1" , "type" : "Patch" , "attributedTo" : "https://forge.example/luke" , "context" : "https://dev.example/aviva/game-of-life/pulls/825/versions/1" , "mediaType" : "application/x-git-patch" , "content" : "From c9ae5f4ff4a330b6e1196ceb7db1665bd4c1..." }
Name | TicketDependency |
---|---|
URI | https://forgefed.org/ns#TicketDependency |
Extends | Relationship |
Description | Represents a relationship between 2 Tickets, in which the resolution of
one ticket requires the other ticket to be resolved too. It MUST specify
the subject, object and relationship properties, and the relationship property MUST be dependsOn.
|
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "type" : [ "Relationship" , "TicketDependency" ], "id" : "https://example.dev/ticket-deps/2342593" , "attributedTo" : "https://example.dev/alice" , "summary" : "Alice's ticket depends on Bob's ticket" , "published" : "2019-07-11T12:34:56Z" , "subject" : "https://example.dev/alice/myproj/issues/42" , "relationship" : "dependsOn" , "object" : "https://dev.community/bob/coolproj/issues/85" }
Name | Ticket |
---|---|
URI | https://forgefed.org/ns#Ticket |
Extends | Object |
Description | Represents an item that requires work or attention. Tickets exist in the context of a project (which may or may not be a version-control repository), and are used to track ideas, proposals, tasks, bugs and more. |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "type" : "Ticket" , "id" : "https://example.dev/alice/myrepo/issues/42" , "context" : "https://example.dev/alice/myrepo" , "attributedTo" : "https://dev.community/bob" , "summary" : "Nothing works!" , "content" : "<p>Please fix. <i>Everything</i> is broken!</p>" , "mediaType" : "text/html" , "source" : { "content" : "Please fix. *Everything* is broken!" , "mediaType" : "text/markdown; variant=CommonMark" }, "assignedTo" : "https://example.dev/alice" , "isResolved" : false }
8.2. Properties
8.2.1. General-purpose
Name | earlyItems |
---|---|
URI | https://forgefed.org/ns#earlyItems |
Domain | OrderedCollection |
Range | Ordered list of [ Object | Link ] |
Functional | No |
Inverse of | None |
Description | In an ordered collection (or an ordered collection page) in which items (or orderedItems) contains a continuous subset of the collection’s
items from one end, earlyItems identifiers a continuous subset from the
other end. For example, if items lists the chronologically latest items, earlyItems would list the chrologically earliest items. The ordering rule
for items in earlyItems MUST be the same as in items . For examle, if items lists items in reverse chronogical order, then so does earlyItems .
|
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://dev.example/aviva/outbox" , "type" : "OrderedCollection" , "totalItems" : 712 , "orderedItems" : [ "https://dev.example/aviva/outbox/712" , "https://dev.example/aviva/outbox/711" , "https://dev.example/aviva/outbox/710" ], "earlyItems" : [ "https://dev.example/aviva/outbox/3" , "https://dev.example/aviva/outbox/2" , "https://dev.example/aviva/outbox/1" ] }
Name | previousVersions |
---|---|
URI | https://forgefed.org/ns#previousVersions |
Domain | Object |
Range | rdf:List of objects of the same @type as the subject
|
Functional | Yes |
Inverse of | None, but see currentVersion |
Description | Specifies the previous versions of the subject, as an ordered list in reverse chronological order. |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://dev.example/aviva/notes/107" , "type" : "Note" , "attributedTo" : "https://dev.example/aviva" , "content" : "I agree!!!!! (edit: fixed a typo)" , "previousVersions" : [ "https://dev.example/aviva/notes/107_old_version" , "https://dev.example/aviva/notes/107_very_old_version" , "https://dev.example/aviva/notes/107_ancient_version" ] }
Name | currentVersion |
---|---|
URI | https://forgefed.org/ns#currentVersion |
Domain | Object |
Range | Object, of the same @type as the subject
|
Functional | Yes |
Inverse of | None, but see previousVersions |
Description | Specifies the latest. current, up-to-date version of the subject. Once the
subject specifies the currentVersion property, it SHOULD NOT get any
changes to any other properties. The exception is currentVersion itself,
which MUST be updated whenever needed, to always point to the latest
version.
|
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://dev.example/aviva/notes/107_old_version" , "type" : "Note" , "attributedTo" : "https://dev.example/aviva" , "content" : "I agree!!111" , "currentVersion" : "https://dev.example/aviva/notes/107" }
8.2.2. Factories
Name | availableActorTypes |
---|---|
URI | https://forgefed.org/ns#availableActorTypes |
Domain | Factory |
Range | URI |
Functional | No |
Inverse of | None |
Description | Specifies the actor types that can be created via this Factory. |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://w3id.org/security/v2" , "https://forgefed.org/ns" ], "id" : "https://grape.fr33domlover.site/factories/YGQoZ" , "type" : "Factory" , "name" : "final-factory" , "summary" : "." , "availableActorTypes" : [ "TicketTracker" , "Project" , "Team" , "Repository" ], "outbox" : "https://grape.fr33domlover.site/factories/YGQoZ/outbox" , "publicKey" : [ "https://grape.fr33domlover.site/akey1" , "https://grape.fr33domlover.site/akey2" ], "collaborators" : "https://grape.fr33domlover.site/factories/YGQoZ/collabs" , "followers" : "https://grape.fr33domlover.site/factories/YGQoZ/followers" , "inbox" : "https://grape.fr33domlover.site/factories/YGQoZ/inbox" , "teams" : "https://grape.fr33domlover.site/factories/YGQoZ/teams" }
8.2.3. Projects
Name | components |
---|---|
URI | https://forgefed.org/ns#components |
Domain | Project |
Range | Collection |
Functional | Yes |
Inverse of | None, but see the usage of context in the Modeling specification, e.g. in § 6.7 Repository |
Description | Identifies a Collection listing actors whose services and resources are considered to be components of this project. |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://dev.example/projects/wanderer" , "type" : "Project" , "name" : "Wanderer" , "summary" : "3D nature exploration game" , "components" : { "type" : "Collection" , "totalItems" : 7 , "items" : [ "https://dev.example/repos/opengl-vegetation" , "https://dev.example/repos/opengl-vegetation/patch-tracker" , "https://dev.example/repos/treesim" , "https://dev.example/repos/treesim/patch-tracker" , "https://dev.example/repos/wanderer" , "https://dev.example/repos/wanderer/patch-tracker" , "https://dev.example/issue-trackers/wanderer" ] }, "inbox" : "https://dev.example/projects/wanderer/inbox" , "outbox" : "https://dev.example/projects/wanderer/outbox" , "followers" : "https://dev.example/projects/wanderer/followers" }
Name | subprojects |
---|---|
URI | https://forgefed.org/ns#subprojects |
Domain | Project |
Range | Collection of Projects |
Functional | Yes |
Inverse of | None, but see the usage of context in § 6.4 Project |
Description | Identifies a Collection listing the subprojects of this Project. |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://dev.example/projects/wanderer" , "type" : "Project" , "name" : "Wanderer" , "summary" : "3D nature exploration game" , "subprojects" : { "type" : "Collection" , "totalItems" : 2 , "items" : [ "https://dev.example/projects/nature-3d-models" , "https://dev.example/projects/wanderer-fundraising" ] }, "inbox" : "https://dev.example/projects/wanderer/inbox" , "outbox" : "https://dev.example/projects/wanderer/outbox" , "followers" : "https://dev.example/projects/wanderer/followers" }
8.2.4. Team membership and nesting
Name | hasMember |
---|---|
URI | https://forgefed.org/ns#hasMember |
Domain | Team |
Range | Person |
Functional | No |
Inverse of | None |
Description | Identifier a Person who is a member of this Team. |
Name | members |
---|---|
URI | https://forgefed.org/ns#members |
Domain | Team |
Range | Collection of Relationships whose relationship is hasMember and whose subject is this Team .
|
Functional | Yes |
Inverse of | None |
Description | Identifies a collection of the members of this Team, represented as hasMember Relationships. |
Name | subteams |
---|---|
URI | https://forgefed.org/ns#subteams |
Domain | Team |
Range | Collection of Teams. |
Functional | Yes |
Inverse of | None |
Description | Identifies a collection of the subteams of this Team, i.e. teams whose members inherit the access that this team’s members have to projects and to project components (such as Repositorys). |
Name | hasRecursiveCollaborator |
---|---|
URI | https://forgefed.org/ns#hasRecursiveCollaborator |
Domain | Resource actor that isn’t Team |
Range | Team |
Functional | No |
Inverse of | None |
Description | Identifier a Team that’s been granted access to this resource. |
Name | teams |
---|---|
URI | https://forgefed.org/ns#teams |
Domain | An actor of type that isn’t Team |
Range | Collection of Relationship objects, in each of which subject is a resource actor’s URI, relationship is hasRecursiveCollaborator, object is a Team’s URI and instrument is the role given to that team in that resource. |
Functional | Yes |
Inverse of | None (but see teamResources) |
Description | Identifies a collection of the resources this Team has access to, and that it is delegating to its members and subteams. |
Name | teamResources |
---|---|
URI | https://forgefed.org/ns#teamResources |
Domain | Team |
Range | Collection of Relationship objects, in each of which subject is a resource actor’s URI, relationship is hasRecursiveCollaborator, object is a Team’s URI and instrument is the role given to that team in that resource. |
Functional | Yes |
Inverse of | None (but see teams) |
Description | Identifies a collection of the Teams that have access to this resource, and are delegating it to their members and subteams. |
8.2.5. Ticket assignment and resolution
Name | assignedTo |
---|---|
URI | https://forgefed.org/ns#assignedTo |
Domain | Ticket |
Range | Person |
Functional | Yes |
Inverse of | None |
Description | Identifies the Person assigned to work on this Ticket. |
Name | isResolved |
---|---|
URI | https://forgefed.org/ns#isResolved |
Domain | Ticket |
Range | xsd:boolean
|
Functional | Yes |
Inverse of | None |
Description | Specifies whether the Ticket is closed, i.e. the work on it is done and it doesn’t need to attract attention anymore. |
Name | resolvedBy |
---|---|
URI | https://forgefed.org/ns#resolvedBy |
Domain | Ticket |
Range | Object than is an actor, or Activity |
Functional | Yes |
Inverse of | None |
Description | Identifies the Actor who has resolved the Ticket, or the activity that has resolved the Ticket. |
Name | resolved |
---|---|
URI | https://forgefed.org/ns#resolved |
Domain | Ticket |
Range | xsd:dateTime
|
Functional | Yes |
Inverse of | None |
Description | For a resolved Ticket, specifies the time the Ticket has been resolved. |
8.2.6. Ticket dependencies
Name | dependsOn |
---|---|
URI | https://forgefed.org/ns#dependsOn |
Domain | Ticket |
Range | Ticket |
Functional | No |
Inverse of | dependedBy |
Description | Identifies one or more tickets on which this Ticket depends, i.e. it can’t be resolved without those tickets being resolved too. |
Name | dependedBy |
---|---|
URI | https://forgefed.org/ns#dependedBy |
Domain | Ticket |
Range | Ticket |
Functional | No |
Inverse of | dependsOn |
Description | Identifies one or more tickets which depend on this Ticket, i.e. they can’t be resolved without this tickets being resolved too. |
Name | dependencies |
---|---|
URI | https://forgefed.org/ns#dependencies |
Domain | Ticket |
Range | Collection of items of type TicketDependency |
Functional | Yes |
Inverse of | None |
Description | Identifies a Collection of TicketDependency which specify tickets that this Ticket depends on, i.e. this ticket is the subject of the dependsOn relationship. |
Name | dependants |
---|---|
URI | https://forgefed.org/ns#dependants |
Domain | Ticket |
Range | Collection of items of type TicketDependency |
Functional | Yes |
Inverse of | None |
Description | Identifies a Collection of TicketDependency which specify tickets that depends on this Ticket, i.e. this ticket is the object of the dependsOn relationship. Often called "reverse dependencies". |
8.2.7. Repository cloning
Name | cloneUri |
---|---|
URI | https://forgefed.org/ns#cloneUri |
Domain | Repository |
Range | Object |
Functional | No |
Inverse of | None |
Description | An endpoint that can be used with a VCS protocol such as Git or Mercurial to access a given repository. |
8.2.8. Repository pushing
Name | hashBefore |
---|---|
URI | https://forgefed.org/ns#hashBefore |
Domain | Push |
Range | xsd:string of hexadecimal digit ASCII characters
|
Functional | Yes |
Inverse of | None |
Description | Specifies the hash of the commit that the pushed branch/repo was pointing to right before the push happpened. |
Name | hashAfter |
---|---|
URI | https://forgefed.org/ns#hashAfter |
Domain | Push |
Range | xsd:string of hexadecimal digit ASCII characters
|
Functional | Yes |
Inverse of | None |
Description | Specifies the hash of the commit that the pushed branch/repo was pointing to right after the push happpened. |
8.2.9. Commits and branches
Name | repository (DEPRECATED) |
---|---|
URI | https://forgefed.org/ns#repository |
Domain | Commit |
Range | Repository |
Functional | Yes |
Inverse of | None |
Description | |
Identifies the repository to which a commit belongs. DEPRECATED | Use the
standard ActivityPub context property instead.
|
Name | description |
---|---|
URI | https://forgefed.org/ns#description |
Domain | Commit |
Range | Object, specifying content and mediaType. The mediaType SHOULD be "text/plain" .
|
Functional | Yes |
Inverse of | None |
Description | Specifies the description text of a Commit, which is an optional
possibly multi-line text provided in addition to the one-line commit title.
The range of the description property works the same way the range of the
ActivityPub source property works.
|
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://example.dev/alice/myrepo/commits/109ec9a09c7df7fec775d2ba0b9d466e5643ec8c" , "type" : "Commit" , "context" : "https://example.dev/alice/myrepo" , "attributedTo" : "https://example.dev/bob" , "hash" : "109ec9a09c7df7fec775d2ba0b9d466e5643ec8c" , "created" : "2019-07-11T12:34:56Z" , "summary" : "Add an installation script, fixes issue #89" , "description" : { "mediaType" : "text/plain" , "content" : "It's about time people can install on their computers!" }, }
Name | committedBy |
---|---|
URI | https://forgefed.org/ns#committedBy |
Domain | Commit |
Range | Object |
Functional | Yes |
Inverse of | None |
Description | Identifies the actor (usually a person, but could be something else, e.g. a
bot) that added a set of changes to the version-control Repository.
Sometimes the author of the changes and the committer of those changes
aren’t the same actor, in which case the committedBy property can be used
to specify who added the changes to the repository. For example, when
applying a patch to a repository, e.g. a Git repository, the author would
be the person who made the patch, and the committer would be the person who
applied the patch to their copy of the repository.
|
Name | hash |
---|---|
URI | https://forgefed.org/ns#hash |
Domain | Commit |
Range | xsd:string of hexadecimal digit ASCII characters
|
Functional | Yes |
Inverse of | None |
Description | Specifies the hash associated with a Commit, which is a unique identifier of the commit within the Repository, usually generated as a cryptographic hash function of some (or all) of the commit’s data or metadata. For example, in Git it would be the SHA1 hash of the commit; in Darcs it would be the SHA1 hash of the patch info. |
Name | committed |
---|---|
URI | https://forgefed.org/ns#committed |
Domain | Commit |
Range | xsd:dateTime
|
Functional | Yes |
Inverse of | None |
Description | Specifies the time that a set of changes was committed into the Repository and became a Commit in it. This can be different from
the time the set of changes was produced, e.g. if one person creates a
patch and sends to another, and the other person then applies the patch to
their copy of the repository. We call the former event "created" and the
latter event "committed", and this latter event is specified by the committed property.
|
Name | filesAdded |
---|---|
URI | https://forgefed.org/ns#filesAdded |
Domain | Commit |
Range | xsd:string
|
Functional | No |
Inverse of | None |
Description | Specifies a filename, as a relative path, relative to the top of the tree of files in the Repository, of a file that got added in this Commit, and didn’t exist in the previous version of the tree. |
Name | filesModified |
---|---|
URI | https://forgefed.org/ns#filesModified |
Domain | Commit |
Range | xsd:string
|
Functional | No |
Inverse of | None |
Description | Specifies a filename, as a relative path, relative to the top of the tree of files in the Repository, of a file that existed in the previous version of the tree, and its contents got modified in this Commit. |
Name | filesRemoved |
---|---|
URI | https://forgefed.org/ns#filesRemoved |
Domain | Commit |
Range | xsd:string
|
Functional | No |
Inverse of | None |
Description | Specifies a filename, as a relative path, relative to the top of the tree of files in the Repository, of a file that existed in the previous version of the tree, and got removed from the tree in this Commit. |
Name | ref |
---|---|
URI | https://forgefed.org/ns#ref |
Domain | Branch |
Range | xsd:string
|
Functional | Yes |
Inverse of | None |
Description | Specifies an identifier for a Branch, that is used in the Repository to uniquely refer to it. For example, in Git,
"refs/heads/master" would be the ref of the master branch.
|
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://example.dev/luke/myrepo/branches/master" , "type" : "Branch" , "name" : "master" , "context" : "https://example.dev/luke/myrepo" , "ref" : "refs/heads/master" }
8.2.10. Activity addressing
Name | team |
---|---|
URI | https://forgefed.org/ns#team |
Domain | Object |
Range | Collection of actors |
Functional | Yes |
Inverse of | None |
Description | Specifies a Collection of actors who are working on the object, or responsible for it, or managing or administrating it, or having edit access to it. For example, for a Repository, it could be the people who have push/edit access, the "collaborators" of the repository. |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://w3id.org/security/v1" , "https://forgefed.org/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" , "name" : "Tree Growth 3D Simulation" , "summary" : "<p>Tree growth 3D simulator for my nature exploration game</p>" , "team" : "https://dev.example/aviva/treesim/team" }
The repository’s team https://dev.example/aviva/treesim/team:
{ "@context" : "https://www.w3.org/ns/activitystreams" , "id" : "https://dev.example/aviva/treesim/team" , "type" : "Collection" , "totalItems" : 3 , "items" : [ "https://dev.example/aviva" , "https://dev.example/luke" , "https://code.community/users/lorax" ] }
8.2.11. Tracker linking
Name | ticketsTrackedBy |
---|---|
URI | https://forgefed.org/ns#ticketsTrackedBy |
Domain | Object |
Range | Object that is an actor |
Functional | Yes |
Inverse of | tracksTicketsFor |
Description | Identifies the actor which tracks tickets related to the given object. This is the actor to whom you send tickets you’d like to open against the object. |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://dev.example/aviva/treesim" , "type" : "Repository" , "name" : "Tree Growth 3D Simulation" , "summary" : "<p>Tree growth 3D simulator for my nature exploration game</p>" , "ticketsTrackedBy" : "https://bugs.example/projects/treesim" }
Name | tracksTicketsFor |
---|---|
URI | https://forgefed.org/ns#tracksTicketsFor |
Domain | Object that is an actor |
Range | Object |
Functional | No |
Inverse of | ticketsTrackedBy |
Description | Identifies objects for which which this ticket tracker tracks tickets. When you’d like to open a ticket against those objects, you can send them to this tracker. |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://bugs.example/treesim" , "type" : "Project" , "tracksTicketsFor" : [ "https://dev.example/aviva/liblsystem" , "https://dev.example/aviva/3d-tree-models" , "https://dev.example/aviva/treesim" ] }
Name | sendPatchesTo |
---|---|
URI | https://forgefed.org/ns#sendPatchesTo |
Domain | Repository |
Range | PatchTracker |
Functional | Yes |
Inverse of | tracksPatchesFor |
Description | Identifies the PatchTracker which tracks patches and merge requests related to the given repository. This is the actor to whom you send patches and merge requests you’d like to open against the repository. |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://dev.example/repos/treesim" , "type" : "Repository" , "name" : "Tree Growth 3D Simulation" , "summary" : "<p>Tree growth 3D simulator for my nature exploration game</p>" , "sendPatchesTo" : "https://bugs.example/pr-trackers/treesim" }
Name | tracksPatchesFor |
---|---|
URI | https://forgefed.org/ns#tracksPatchesFor |
Domain | PatchTracker |
Range | Repository |
Functional | No |
Inverse of | sendPatchesTo |
Description | Identifies a repository for which which this patch and merge request tracker tracks patches and merge requests. When you’d like to open patches or merge requests against that repository, you can send them to this tracker. |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://project.example/treesim" , "type" : "PatchTracker" , "tracksPatchesFor" : [ "https://dev.example/aviva/liblsystem" , "https://dev.example/aviva/3d-tree-models" , "https://dev.example/aviva/treesim" ] }
8.2.12. Repository forking
Name | forkedFrom |
---|---|
URI | https://forgefed.org/ns#forkedFrom |
Domain | Repository |
Range | Repository |
Functional | Yes |
Inverse of | forks |
Description | Identifies the Repository which this Repository was created as a fork of, i.e. by cloning it. |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://example.dev/alice/myfork/" , "type" : "Repository" , "forkedFrom" : { "type" : "Repository" , "id" : "https://example.dev/luke/myrepo/" } }
Name | forks |
---|---|
URI | https://forgefed.org/ns#forks |
Domain | Repository |
Range | OrderedCollection of items of type Repository |
Functional | Yes |
Inverse of | forkedFrom |
Description | Identifies an OrderedCollection of Repositorys which were created as forks of this Repository, i.e. by cloning it. The order of the collection items is by reverse chronological order of the forking events. |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://example.dev/luke/myrepo/" , "type" : "Repository" , "forks" : { "type" : "OrderedCollection" , "totalItems" : 1 , "orderedItems" : [ { "id" : "https://example.dev/alice/myfork/" , "type" : "Repository" , } ] }, }
8.2.13. Access control
Name | fulfills |
---|---|
URI | https://forgefed.org/ns#fulfills |
Domain | Activity |
Range | Activity |
Functional | No |
Inverse of | None |
Description | For an activity A that fulfills some other activity B, specifies that A has been published as part of fulfilling the action requested by B.
For example, if Alice creates a new repository using Create , she may want
to instantly automatically start following this new repository using Follow (to be notified when her friends push commits there). This Follow fulfills the Create ; it’s an activity automatically sent as
part of creating a new repository.
|
Name | allows |
---|---|
URI | https://forgefed.org/ns#allows |
Domain | Grant |
Range | CapabilityUsage |
Functional | No |
Inverse of | None |
Description | Specifies which modes of using this Grant are being allowd by it. The
two conceptual operations that Grant s support are invocation (acting on
the resource under the specified role) and delegation (passing on the
access to more actors, possibly with reduced privileges). This property
specifies which of these operations are supported, and under which
conditions. See CapabilityUsage for specific values to use.
|
Name | capability |
---|---|
URI | https://forgefed.org/ns#capability |
Domain | Activity |
Range | Grant |
Functional | Yes |
Inverse of | None |
Description | Specifies a previously published Grant activity providing relevant
access permissions. For example, if Alice wants to resolve a Ticket under some project, she will send an activity with capability referring
to the Grant activity that gave her collaborator access to that project,
which happens to include permission to resolve tickets.
|
Name | publicCapability |
---|---|
URI | https://forgefed.org/ns#publicCapability |
Domain | Object |
Range | Grant |
Functional | No |
Inverse of | None |
Description | Specifies a Grant activity providing access to the Public, i.e. a Grant that any user/actor can use to interact with the object. |
Name | managedBy |
---|---|
URI | https://forgefed.org/ns#managedBy |
Domain | Object |
Range | Object that is an actor |
Functional | Yes |
Inverse of | None |
Description | Identifies the actor that controls the given resource, and to whom activities asking to modify the resource may be submitted. |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "type" : "Ticket" , "id" : "https://example.dev/alice/myrepo/issues/42" , "context" : "https://example.dev/alice/myrepo" , "managedBy" : "https://example.dev/alice/myrepo" , "attributedTo" : "https://dev.community/bob" , "summary" : "Nothing works!" , "content" : "<p>Please fix. <i>Everything</i> is broken!</p>" , "mediaType" : "text/html" , "source" : { "content" : "Please fix. *Everything* is broken!" , "mediaType" : "text/markdown; variant=CommonMark" }, "isResolved" : false }
Name | delegates |
---|---|
URI | https://forgefed.org/ns#delegates |
Domain | Grant |
Range | Grant |
Functional | Yes |
Inverse of | None |
Description | Actors can use Grant activities to allow other actors to access their
resources. They can also allow those other actors to pass on (delegate)
this access to even more actors. For a Grant that delegates access
provided by an earlier Grant , the former uses delegates to specify the
latter. That earlier Grant is also called the "parent capability" of this Grant .
|
Name | hasCollaborator |
---|---|
URI | https://forgefed.org/ns#hasCollaborator |
Domain | Actor |
Range | Actor |
Functional | No |
Inverse of | None |
Description | For a given actor A, specifies an actor B who has been giving a direct Grant to access/manipulate A |
Name | collaborators |
---|---|
URI | https://forgefed.org/ns#collaborators |
Domain | Actor |
Range | A Collection of Relationship objects |
Functional | Yes |
Inverse of | None |
Description | A collection of the direct collaborators of the actor, i.e. actors that have been given a direct-Grant to it. In each Relationship object, the subject is the actor, relationship is hasCollaborator, object is the collaborator and instrument is the role. |
8.2.14. Repository mirroring
Name | mirrors |
---|---|
URI | https://forgefed.org/ns#mirrors |
Domain | Repository |
Range | Repository |
Functional | Yes |
Inverse of | mirroredBy |
Description | Identifies the Repository which this Repository copies content from (i.e. what this repository is a "pull mirror" of). |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://example.dev/alice/mymirror/" , "type" : "Repository" , "mirrors" : { "type" : "Repository" , "id" : "https://example.dev/luke/myrepo/" } }
Name | mirroredBy |
---|---|
URI | https://forgefed.org/ns#mirroredBy |
Domain | Repository |
Range | Repository |
Functional | No |
Inverse of | mirrors |
Description | Identifies a Repository which copies content from this repository (i.e. "pull mirror" of this repository). |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://example.dev/luke/myrepo/" , "type" : "Repository" , "mirroredBy" : { "type" : "Repository" , "id" : "https://example.dev/alice/mymirror/" } }
Name | mirrorsTo |
---|---|
URI | https://forgefed.org/ns#mirrorsTo |
Domain | Repository |
Range | Repository |
Functional | No |
Inverse of | mirroredFrom |
Description | Identifies a Repository which this repository copies content to (i.e. "push mirror" of this repository) |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://example.dev/alice/myrepo/" , "type" : "Repository" , "mirrorsTo" : { "type" : "Repository" , "id" : "https://example.dev/alice-backup/myrepo/" } }
Name | mirroredFrom |
---|---|
URI | https://forgefed.org/ns#mirroredFrom |
Domain | Repository |
Range | Repository |
Functional | Yes |
Inverse of | mirrorsTo |
Description | Identifies the Repository which copies its content to this Repository (ie. what this repository is a "push mirror" of). |
{ "@context" : [ "https://www.w3.org/ns/activitystreams" , "https://forgefed.org/ns" ], "id" : "https://example.dev/alice-backup/myrepo/" , "type" : "Repository" , "mirroredFrom" : { "type" : "Repository" , "id" : "https://example.dev/alice/myrepo/" } }
8.3. Values
8.3.1. Capability uses
Name | gatherAndConvey |
---|---|
URI | https://forgefed.org/ns#gatherAndConvey |
Type | CapabilityUsage |
Conditions |
Name | distribute |
---|---|
URI | https://forgefed.org/ns#distribute |
Type | CapabilityUsage |
Conditions |
Name | invoke |
---|---|
URI | https://forgefed.org/ns#invoke |
Type | CapabilityUsage |
Conditions |
|
8.3.2. Roles
Name | visit |
---|---|
URI | https://forgefed.org/ns#visit |
Type | Role |
Description | Authorizes the Grant recipient (i.e. target) to view the Grant resource (i.e. context), which includes retrieving objects via HTTP and pulling/cloning VCS repos |
Name | report |
---|---|
URI | https://forgefed.org/ns#report |
Type | Role |
Description | Authorizes the Grant recipient (i.e. target) to do on the Grant resource (i.e. context) anything that the visit role authorizes, |
and also to do basic community participation tasks | Open an issue, submit a PR, create comments and discussion threads, edit public wikis, submit PR reviews. |
Name | triage |
---|---|
URI | https://forgefed.org/ns#triage |
Type | Role |
Description | Authorizes the Grant recipient (i.e. target) to do on the Grant resource (i.e. context) anything that the report role authorizes, and also to edit issue/PR propeties (labels, milestones, due dates, etc.), close and reopen issues and PRs, assign and unassign people to issues and PRs, request PR reviews, hide disruptive comments (a moderation action), lock and move discussions. |
Name | write |
---|---|
URI | https://forgefed.org/ns#write |
Type | Role |
Description | Authorizes the Grant recipient (i.e. target) to do on the Grant resource (i.e. context) anything that the triage role authorizes, and also to apply PR suggested changes, edit non-public wikis, create/edit/delete labels, merge a PR, push to VCS repositories, create/edit/run/cancel CI recipes, manage releases, publish packages, create web IDE coding sessions. |
Name | maintain |
---|---|
URI | https://forgefed.org/ns#maintain |
Type | Role |
Description | Authorizes the Grant recipient (i.e. target) to do on the Grant resource (i.e. context) anything that the write role authorizes, and also to edit project and component descriptions and settings unrelated to access, enable/disable components, configure "Pages" publishing of static websites from repos, push to repos' protected branches. |
Name | admin |
---|---|
URI | https://forgefed.org/ns#admin |
Type | Role |
Description | Authorizes the Grant recipient (i.e. target) to do on the Grant resource (i.e. context) anything that the maintain role authorizes, and also to manage access to projects, components and teams, merge PRs even without reviews, delete issues, change project/component/team visibility, edit project/component/team access-related settings, change a repo’s default branch, manage webhooks and deployment, move components and projects between projects, archive projects/components, delete components/projects/teams. |
Name | delegate |
---|---|
URI | https://forgefed.org/ns#delegate |
Type | Role |
Description | Authorizes the Grant recipient (i.e. target) to send access delegations to the Grant sender (i.e. actor) |