ForgeFed Modeling - draft - 2023-03-08 main a3a6d7d
1 Abstract
This document describes the rules and guidelines for representing version control and project management related objects as linked data, using the ForgeFed vocabulary, ActivityStreams 2, and other related vocabularies.
2 Introduction
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.
3 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 xsd: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” andcontent
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)
Example:
{
"@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!"
}
}
4 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
Example:
{
"@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..."
}
5 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. “master”
- ref: The unique identifier of the branch within the repo, e.g. “refs/heads/master”
- 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
Example:
{
"@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 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
Example:
{
"@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>"
}
7 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
Example:
{
"@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"
}
8 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
Example:
{
"@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": "https://roles.example/developer"
}
9 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 (see details in Vocabulary specification)
- 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)
Example:
{
"@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": "https://roles.example/maintainer"
},
{ "type": "Relationship",
"subject": "https://dev.example/teams/mobilizon-dev-team",
"relationship": "hasMember",
"object": "https://dev.example/people/celine",
"tag": "https://roles.example/developer"
}
]
},
"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"
}
10 Push
To represent an event of Commits being pushed to a Repository, use a ForgeFed Push activity.
Properties:
- type: “Push”
- actor: The entity (person, bot, etc.) that pushed the commits
- context: The Repository to which the push was made
- 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 context. And if it’s a repository, it MUST be identical to the one specified by context.
- 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).
Example:
{
"@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"
}
]
}
}
11 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.
11.1 Task / Issue
A task is represented as a 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)
Example:
{
"@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"
}
11.2 Merge Request / Pull Request
A merge request is represented as a 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:
- type is 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 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
Example:
{
"@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"
}
}
}
12 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
Example:
{
"@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"
}
13 Access Control
13.1 Giving Access
13.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 theactor
permission to invite more actors to access the resource
Example:
{
"@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": "https://roles.example/maintainer",
"target": "https://coding.community/repos/game-of-life",
"object": "https://software.site/bob",
"capability": "https://coding.community/repos/game-of-life/outbox/2c53A"
}
13.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 theactor
permission to gain access to the resource without the approval of another actor. Ifcapability
isn’t provided, the resource won’t grant access before someone with adequate access approves the Join request.
Example:
{
"@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": "https://roles.example/maintainer",
"object": "https://coding.community/repos/game-of-life",
"capability": "https://coding.community/repos/game-of-life/outbox/d38Fa"
}
13.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 relatedInvite
(another example: if Alice Creates a new repository, the repository may automatically send back a Grant giving Alice admin access, and this Grant’sfulfills
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
- 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 parentGrant
that it has received and now passing on
Example:
{
"@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": "https://roles.example/maintainer",
"context": "https://coding.community/repos/game-of-life",
"target": "https://software.site/bob",
"fulfills": "https://dev.example/aviva/outbox/B47d3",
"allows": "invoke"
}
13.2 Canceling Access
13.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 theactor
permission to disable the object actor’s access to the resource
Example:
{
"@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"
}
13.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)
Example:
{
"@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"
}
13.2.3 Revoke
Another activity that can be used for disabling access is Revoke. While Remove and Leave are meant for undoing the effects of Invite and Join, Revoke
is provided as an opposite of 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
- instrument: The Role that the origin actor had with respect to accessing the resource, and which is now being taken away
- context: The resource, access to which is being revoked
- origin: The actor whose access to the resource is being revoked
- fulfills: An activity that triggered the sending of the
Grant
, such as a relatedRemove
orLeave
- object: specific 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
Example:
{
"@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"
],
"instrument": "https://roles.example/maintainer",
"context": "https://coding.community/repos/game-of-life",
"origin": "https://software.site/bob",
"object": "https://coding.community/repos/game-of-life/outbox/9fA8c"
}
13.2.4 Undo a Grant
The Behavior spec describes flows in which the Revoke activity is used by resources (more accurately, by the actors managing them) to announce that they’re disabling 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 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 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 theactor
permission to disable the object actor’s access to the resource