Projects & Grant Chains
2023-11-13 by Pere Lev
It's been 5 months since the previous blog post! Much longer than I hoped. The features I've been working on proved to be much more complex to implement, than I anticipated. With the frustration and exhaustion building up, I kept working in small chunks, and the result is finally here.
After all the many words below there's a demo as well.
Take a look at my task board for more context while reading.
Vervis and OCAPs
A bit of background just in case you missed it. I've been working in 2 channels:
- Make updates and additions to the ForgeFed specification
- Implementing them in Vervis, a proof-of-concept reference-implementation ForgeFed server written in Haskell
One of my primary topics has been Object Capabilities (or OCAPs), which are decentralized authorization tokens. They're a core piece of how federated authorization works in ForgeFed. For more info about OCAPs, see the previous blog posts.
I'll just say this: Giving permission to access some resource is done in
ForgeFed by sending a Grant activity. That activity can then be used as
authorization when accessing the resource, by specifying the Grant
's id
URI.
Beyond Direct Grants
Until now, Vervis allowed working with projects only in the most direct way:
- You couldn't create a whole project in one click
- You could create just a stand-alone component, such as a Git repository or an issue tracker
- After creation, the component sends you a
Grant
activity, giving you full admin access to the component - You can now specify that Grant's
id
URI in thecapability
field of activities that request access/modification of the componet (e.g. change settings; close an issue; merge a PR; etc.)
That sort of Grant is what I call a direct Grant. It goes straight from the resource to the person who's being given access.
This might work nicely on a very small scale, but if we want to be serious and effective about our work, we'd probably eventually face at least some of these 3 challenges:
- How do we meaningfully group components into projects? Much like on GitHub, GitLab, Gitea, Forgejo etc. a "repository" is actually a multi-component unit that contains code, issues, PRs, releases, kanban, wiki, CI, etc. etc.
- How do we create a flexible way to arrange projects according to the organizational structure of our team/company/organization, to make access management simple?
- How do we use OCAPs/Grants effectively to send out all the necessary authorizations, especially with the complexity of a federated situation?
Today we're visiting especially 1 and 3. A future blog post (along with the implementation of course) will touch point 2.
The Project Actor
Software development components can be collected under projects. I've implemented project creation, viewing and browsing, which is task V5 on my task list, in the following commits:
- Vocabulary and DB schema
- View handlers and creation UI
- C2S handlers for project creation
- S2S handlers for project creation
- S2S project handlers
- HTML page for projects
- Project component list view
You'll see this stuff in action in the demo below.
Adding Components to Projects
So, now we can create projects. How do we add components into these projects? That part has been the bulk of my work in the last few months, because it involved the implementation of 2 complicated pieces:
- The latest full OCAP verification process already present in the ForgeFed specification, i.e. including support for OCAP chains (so far I've implemented only the simple direct mode)
- The sequence of activity handlers that implement the process of adding a component to a project
I've mentioned OCAP delegation before, but let's look at it again, perhaps with a simple example this time. Given:
- A project P and its component C which is an issue tracker
- A person Alice who has maintainer access to P
When Alice wants to close one of the issues under C, what sort of token can she provide, in order to authorize the action? She doesn't have a direct Grant from C, only access to P, so how does this work?
The magic is OCAP chains. C gives P a special Grant that says: "Hi P! You can extend this Grant to whoever has access to you, so that they can access me as well." And now P can extend, or "delegate" this Grant, by sending Alice a new Grant that links to the Grant that P got from C. So we have a chain of 2 Grants:
- C gives a Grant to P, let's call it g
- P gives a Grant to Alice, let's call it h
So, when Alice wants to ask C to close one of the issues under it, she uses Grant h as the authorization token. Since h links back to g, C can follow the chain of Grants and verify they form a valid delegation of authority.
Did I succeed at making it sound much simpler than it really is? :)
Now let's look at the sequence of activities required for adding a project to a component. Here's an overview of one of the possible flows.
Given:
- A project P
- A component C
- A person with admin access to C, Alice
- A person with admin access to P, Bob
The process, if initiated by Bob, looks as follows:
- Bob sends an
Invite
activity, inviting C to become a component of P - P approves the initial request and sends an
Accept
- Alice, seeing the invite, sends an Accept to approve the operation on the component side
- C sees all of this and sends an Accept, thus the operation is now approved from both directions
- P sends to C a "delegate-Grant", i.e. a Grant that uses the special
delegate
role, authorizing C to start Grant chains with P as the target - C receives the delegate-Grant and uses it as the authorization as it starts the Grant chain, sending a start-Grant to P
- P now extends this start-Grant as needed, by sending extension-Grants to its member people (and teams and parent projects)
I've implemented all of this, including just enough UI for a little demo, as tasks S4 and V8 on my list. The implementation clearly informed many details in the processes added to the specification (a reminder to the part of me that is tempted to trust theory alone).
The list of commits for this part is quite long, so if you're looking for the essence, the S2S and UI commits are probably the more interesting ones.
- Udates to the specification
- Define process of add/remove component to/from project (not merged yet, at the time of writing)
- Prepare OCAP system for component-mode
- Project side
- S2S: Project Add handler
- UI & Vocab: Project components list & link from collabs JSON to project
- Vocab: Support project/component in parseInvite, update handlers
- S2S, C2S, Client: Update parseRemove to support project+component
- Copy topicInvite impl into projectInvite instead of reusing topicInvite
- S2S: topicInvite, projectInvite: If approved, send an Accept
- DB: Make the Accept unique per CollabFulfillsInvite
- S2S: Upgrade the Project Invite handler to handle components
- Add a ProjectCollabLiveR route for use as Grant revocation URI
- S2S: Copy topicAccept code into projectAccept and reorganize the comment
- S2S: Project Add handler: Rearrange code in preparation for Component mode
- S2S: Update Project-Accept handler to handle Components
- S2S: Project Grant handler
- Component side
- S2S: Deck Add handler
- S2S: Deck Invite handler: Implement component mode
- S2S: Deck Accept handler: Implement component mode
- S2S: Implement component delegator-Grant handler
- S2S: Person Grant handler: Handle component-mode Grants too
- S2S: projectAccept: When adding a Collab, delegate access-to-my-components
- C2S: Invite: Support component mode
- C2S: Implement Add handler, for adding a component to a project
- C2S: Implement Accept handler
- UI: Deck: Projects list page
- Prepare issue/PR tracker handlers for use with OCAP chains
- S2S: Deck: Port the Offer{Ticket} handler from the old code
- S2S: Person: Implement trivial Offer handler
- S2S: Loom: Port Offer{MR} handler from old federation code
- C2S: Implement Offer{ticket/MR} handler
- UI: Use the actor system for opening a ticket, and remove offerTicketC
- S2S: Port Deck's & Loom's Resolve handlers from the old system
- S2S: Person: Trivial Resolve handler
- C2S, UI: Deck ticket closing button on ticket page
- C2S: Implement trivial Undo handler, remove old undoC code
- Client: Port/implement pseudo-client for unresolve-a-ticket
- UI: Add reopen-this-ticket button to ticket page
- Upgrade OCAP system, implementing chain verification
- UI for OCAP-chained closing-a-ticket
Teams and Longer Chains
The Grant chain I mentioned is very simple, just 2 Grants in it. Component sends a Grant to project, then project sends a Grant to Alice. Which might lead us to ask:
- Is that all? All this complexity just for these 2 grants?
- What about teams and organizations? What about a hierarchy of projects that contain other projects? Or decentralized shapes that aren't a tree/pyramid?
So let me clarify: The OCAP verification process can handle chains of any length, including chains that involve teams and hierarchies of teams and projects. Vervis itself doesn't yet allow to create these hierarchies (that belongs to my next tasks, so stay tuned), but the OCAP verification implementation already supports them. So you'll hopefully see them in action soon.
Same for teams themselves, even without hierarchies, they (teams) are only partially implemented, and that's why I haven't included them in the examples. They, too, are on my todo-list to implement soon as part of my next ForgeFed milestones.
Gradually, pieces of the puzzle are falling into place.
Thanks
Huge thanks to my fellow ForgeFed maintainers and developers for their continued work, including the careful review of my PRs!
Huge thanks to NLNet for funding my work on forge federation! (It's the 2nd year, and I'm considering to apply again when the time comes!)
Help Wanted
Perhaps you noticed Vervis has a quite unusable static-HTML UI. A while ago, mray and I started designing a pretty dynamic client application, and we made big progress with the design. But we stopped because I can't keep up on the development side.
Do you have passion for forge federation, and for turning software development into a community activity, where we develop and evolve our own tools, free to play, express ourselves, solve problems and address human needs, not confined to conflicting control and interests?
Do you have experience with frontend development, or willingness to learn?
Are you willing to give it a try, and if all goes well, apply for funding (with our support) to sustain your work?
Come chat with us on Matrix!
For more technical info about the tech stack etc., check out the Anvil repo.
If you aren't into frontend development, there's still plenty of other things to do: Backend development, packaging, documentation, illustration, redesigning of this website, etc. etc.
See It in Action
I recorded a little demo of all this! Watch it on my PeerTube instance.
If you want to play with things yourself, you can create account(s) on the demo instances - fig, grape, walnut - and try the things I've mentioned and done in the video:
- Creating projects and ticket trackers, opening tickets
- Inviting a tracker to a project and approving the invite
- Resolving a ticket using the form, supplying a custom Grant URI that you can find in your inbox or in the project's outbox (or use anything else as the Grant URI and verify that it doesn't work :P)
If you encounter any bugs, let me know! Or open an issue
Comments
We have an account for ForgeFed on the Fediverse: https://floss.social/@forgefed
Right after publishing this post, I'll make a toot there to announce the post, and you can comment there :)