I've been thinking about the experience of new users coming into radicle as we build
the high-level tools and onboarding via `radicle-cli`, and I've come to the conclusion
that a lot of the stuff we're doing should be simplified. As it stands, I think the
identity system is one of the main blockers for building simple UX that will lead to
adoption. There's two core issues with the system as it stands:
1. Doesn't play well with the browser
Users should be able to onboard onto the web and sign payloads in the browser without
having to install anything radicle-specific. This isn't possible today.
2. Friction and encoding as "hidden" branch confuses users and is hard to work with
Working with identities requires specialized tooling, given that they are encoded inside
the monorepo. This is tooling users will have to learn for the sole purpose of updating
identities, adding delegates etc. This applies to personal and project identities.
Users have to work with two *new* identifiers immediately: the PeerId and the Urn.
This is in addition to whatever identifier they already have, eg. an ethereum address, gpg
key or DID. This applies to personal identities.
---
We (alt-clients) could work around these issues, but in the end we won't deliver the UX
we want by taking that approach. Working around (1) will require either a new browser extension,
a local daemon running, or a trusted third-party. Working around (2) is not really possible at the
moment.
I've been mulling over this and talking to others about what an ideal user experience would be,
and one possible experience could look like this:
[New user wanting to open an issue]
* Land on some web app for the first time, on the project page.
* Open the issue tracker and click "create issue".
* Fill in the issue title and description and hit "submit".
* You are prompted to sign the issue payload via a Web3 wallet (Brave wallet, Metamask or mobile wallet).
* The issue is created, with at minimum your ethereum address. If you have an ENS or Ceramic identity
attached to it, more profile information can be filled in.
[User wants to add a second delegate to their project]
* On the CLI, user edits a regular TOML or JSON file in the project source tree and adds a new identity
to the "delegates" field.
* User commits and pushes.
[User wants to add a third delegate to their project]
* On the CLI, user edits the above file, adding the third delegate.
* User creates a new patch with that change, via `rad-patch`, and publishes.
* The second delegate accepts the patch.
* The first user merges the patch.
When it comes to contributing to a project, I think it's ok to ask users to install some tooling, so that
flow would not be so different than what we currently have via `rad-patch`.
---
A bunch of questions are raised with the above: what properties do we preserve of the current system,
what do we lose? I'll try to give a brief overview.
* Verification, quorum rules etc. when updating project identities:
- These would be enforced via one of two mechanisms.
- If a "Patch" COB is available, this sequence of events is verified, ie. multiple "reviews" need to be
present, based on the quorum rules and the file being edited. We can imagine a Radicle.toml file with
the governance rules, ie. the quorum threshold for editing each file:
# Radicle.toml
[file."Radicle.toml"]
threshold = 2
[file."*"]
threshold = 1
[[delegate]]
name = "amy"
key = "..."
[[delegate]]
name = "john"
key = "..."
The above says: To change Radicle.toml, you need two signatures, while to change any other file, you only
need one.
To verify a commit history then, each commit would be verified according to these (changing) rules. This
is the same as we currently do, except we can use familiar workflows for updating permissions and other
metadata.
If we'd prefer this to not rely on access to the Patch COBs for verification, we can embed the signatures as
commit trailers. The `rad-patch` tool would still be required, but verification could be done from
a regular git clone of a repo, and a `rad-verify` tool.
* User identities
- Users can start by installing one of the hundreds of Web3/Ethereum wallets available, create a key and
use that as their identity. If they want more functionality, they can associate that key via a DID with
Ceramic, or a global name, via ENS.
* Multi-device
- We can avoid this entire problem with COBs and signing devices. Users carry their keys on their mobile phone,
and sign payloads that are conflict-free. If there are conflicts, eg. when editing source code, they can be
resolved as usual. However, we should think about whether we want users to have multiple source trees as a "feature".
I personally think it complicates things more than anything.
* Project identity
- The project identity is computed based on the hash of the commit at which the project was initialized. The
identity document is a Radicle.toml file in the source tree. That first commit acts as the root of trust.
* Local first
- User identity metadata being "online" will have to be fetched on demand and potentially cached. This is
an ok compromise. When offline, you'll have the key. If we want a more purist approach ala SSB, it's also possible,
but this will require users to create a new "radicle" identity as we have today.
* Key revocation
- Needs some thought, but presumably, the commits signed by a revoked key can be tracked in a flat file associated
with the project that is an input to the verification process. Yes, you might have to revoke your key for each
project you're actively contributing to, but this is an ok compromise since it happens infrequently (or never) and
simplifies things a lot for everyone else.
---
Open questions
* How does the PeerID play into this? We need it for the initial p2p handshake. In the ideal scenario, users only
ever need to think about a single identifier per user/peer. But if we want users to have more than one source tree,
we need to think about this.
---
Summary
1. Use known tools for project governance
2. Strip down user identities to the bare minimum required to simplify onboarding, and support web usage
Thanks for reading, let me know your thoughts!
I'm still working on a detailed response to this, but I have a few questions I
wanted to clarify:
* How do non-maintainers represent their verified histories? I.e. if I want to
submit a contribution to a repository maintained by someone else do I fork
their repository, then change the verification document to use my keys
(consequently changing the URN), then submit a patch which references the new
URN somehow? I guess you would have to have some tooling to drop the change to
the verification document in the merge commit or similar?
* Relatedly, in the example of posting an issue which you gave. Where does the
COB the user signs end up? We don't have a verified remote for them because
their signature is not on the verification document.
* I'm not sure how you are imagining key revocation to work. If everyone only
has one key and your key is compromised then I suppose you are dependent on
the other project maintainers on the project (if there are any) to update the
set of verified keys?
* What should happen in the case of diverging histories? I.e. if one subset of
maintainers sign one history and another a different history, do we not end up
with all the same UX problems you currently have with peer IDs?
Thanks for the feedback, let me try to reply to these:
------- Original Message -------
On Thursday, August 4th, 2022 at 19:30, Alex Good <alex@memoryandthought.me> wrote:
> > > I'm still working on a detailed response to this, but I have a few questions I> wanted to clarify:> > * How do non-maintainers represent their verified histories? I.e. if I want to> submit a contribution to a repository maintained by someone else do I fork> their repository, then change the verification document to use my keys> (consequently changing the URN), then submit a patch which references the new> URN somehow? I guess you would have to have some tooling to drop the change to> the verification document in the merge commit or similar?
Good question; the way I imagine it, you definitely would *not* edit the identity
document, you would simply add unverified[0] changes to your fork of the canonical
repo. When running `rad-verify` or such tooling, it would be clear that the
last few commits are signed, but not "approved" by the maintainer quorum.
This would always be the case for non-maintainer forks with changes.
[0]: unverified in the sense that they aren't verified by delegates, but the
commit can still be verified to belong to a key/identity. A better term might
be "un-accepted".
When collaborating, it's clear that there will be unverified commits passed
around, until they are merged into the default branch. We could also imagine
that contributors would not really need a `default-branch` checkout, and as
long as unverified changes are on a non-default branch, it doesn't raise
alarms.
> * Relatedly, in the example of posting an issue which you gave. Where does the> COB the user signs end up? We don't have a verified remote for them because> their signature is not on the verification document.
I'm not sure I see the issue here: if we stick to the current monorepo structure,
I could imagine that the cobs would end up under:
/refs/namespaces/<project>/remotes/<contributor-public-key>/cobs
Maybe I'm missing something though?
> * I'm not sure how you are imagining key revocation to work. If everyone only> has one key and your key is compromised then I suppose you are dependent on> the other project maintainers on the project (if there are any) to update the> set of verified keys?
Exactly yes. You simply propose a patch with your key removed from the delegate
set, and optionally a replacement key added. The current maintainer(s) can then
merge that after checking with you out-of-band that you indeed lost your key.
If you are the only signer and you lost your key, then you basically lose "admin"
access to the project.
> * What should happen in the case of diverging histories? I.e. if one subset of> maintainers sign one history and another a different history, do we not end up> with all the same UX problems you currently have with peer IDs?
This would basically require maintainers to equivocate, or "double sign", unless
you set your threshold to a sub-majority. Most probably this is done maliciously
and it will be easy to see who has signed both histories. I'm not sure there is any
difference between the two systems when it concerns diverging histories, is there?
On 04/08/22 06:47pm, Alexis Sellier wrote:
> > * How do non-maintainers represent their verified histories? I.e. if I want to> > submit a contribution to a repository maintained by someone else do I fork> > their repository, then change the verification document to use my keys> > (consequently changing the URN), then submit a patch which references the new> > URN somehow? I guess you would have to have some tooling to drop the change to> > the verification document in the merge commit or similar?>> Good question; the way I imagine it, you definitely would *not* edit the identity> document, you would simply add unverified[0] changes to your fork of the canonical> repo. When running `rad-verify` or such tooling, it would be clear that the> last few commits are signed, but not "approved" by the maintainer quorum.> This would always be the case for non-maintainer forks with changes.>> [0]: unverified in the sense that they aren't verified by delegates, but the> commit can still be verified to belong to a key/identity. A better term might> be "un-accepted".>> When collaborating, it's clear that there will be unverified commits passed> around, until they are merged into the default branch. We could also imagine> that contributors would not really need a `default-branch` checkout, and as> long as unverified changes are on a non-default branch, it doesn't raise> alarms.
In this case you would need to refer to the peer ID when fetching the
project right? What I mean by this is that if you are a maintainer and a
contributor wants to send a PR then you need to fetch their peer IDs
view of the URN right? I suppose this would also rule out contributions
from multiple peer IDs at once (i.e. a patch where multiple peer IDs
have authored it).
>> > * Relatedly, in the example of posting an issue which you gave. Where does the> > COB the user signs end up? We don't have a verified remote for them because> > their signature is not on the verification document.>> I'm not sure I see the issue here: if we stick to the current monorepo structure,> I could imagine that the cobs would end up under:>> /refs/namespaces/<project>/remotes/<contributor-public-key>/cobs>> Maybe I'm missing something though?
Ah gotcha.
>> > * I'm not sure how you are imagining key revocation to work. If everyone only> > has one key and your key is compromised then I suppose you are dependent on> > the other project maintainers on the project (if there are any) to update the> > set of verified keys?>> Exactly yes. You simply propose a patch with your key removed from the delegate> set, and optionally a replacement key added. The current maintainer(s) can then> merge that after checking with you out-of-band that you indeed lost your key.> If you are the only signer and you lost your key, then you basically lose "admin"> access to the project.>> > * What should happen in the case of diverging histories? I.e. if one subset of> > maintainers sign one history and another a different history, do we not end up> > with all the same UX problems you currently have with peer IDs?>> This would basically require maintainers to equivocate, or "double sign", unless> you set your threshold to a sub-majority. Most probably this is done maliciously> and it will be easy to see who has signed both histories. I'm not sure there is any> difference between the two systems when it concerns diverging histories, is there?
Would this not be quite likely to happen in a multi-device single-key
world? If I make some changes on my laptop and push and then also make
some changes on my desktop and push then you now have a diverged history
no?
> > Good question; the way I imagine it, you definitely would not edit the identity> > document, you would simply add unverified[0] changes to your fork of the canonical> > repo. When running `rad-verify` or such tooling, it would be clear that the> > last few commits are signed, but not "approved" by the maintainer quorum.> > This would always be the case for non-maintainer forks with changes.> > > > [0]: unverified in the sense that they aren't verified by delegates, but the> > commit can still be verified to belong to a key/identity. A better term might> > be "un-accepted".> > > > When collaborating, it's clear that there will be unverified commits passed> > around, until they are merged into the default branch. We could also imagine> > that contributors would not really need a `default-branch` checkout, and as> > long as unverified changes are on a non-default branch, it doesn't raise> > alarms.> > > In this case you would need to refer to the peer ID when fetching the> project right? What I mean by this is that if you are a maintainer and a> contributor wants to send a PR then you need to fetch their peer IDs> view of the URN right? I suppose this would also rule out contributions> from multiple peer IDs at once (i.e. a patch where multiple peer IDs> have authored it).>
Yes, I think that aspect of the current system I would keep - ie. how
remotes work. The only thing is the PeerID would have to be an ECDSA
key or whatever we use for the user identity.
Patches from multiple authors would only be possible if the patch
creator cherry-picks commits from another user, I guess. My impression
is that this is a sort of orthogonal issue though.
By the way I'm not ruling out multi-key user identities,
but I Want to be conscious that this introduces a lot of complexity
in the system, eg. you can no longer simply verify signatures given
a list of delegates, you have to also fetch the delegate identities
and keep those updated.
So I'd prefer a design where users start out with just a key, and
later on if users are looking to have these "key rings" we can
support that. But for basic usage I think the key-as-identity model
satisfies most use cases.
> > > * I'm not sure how you are imagining key revocation to work. If everyone only> > > has one key and your key is compromised then I suppose you are dependent on> > > the other project maintainers on the project (if there are any) to update the> > > set of verified keys?> > > > Exactly yes. You simply propose a patch with your key removed from the delegate> > set, and optionally a replacement key added. The current maintainer(s) can then> > merge that after checking with you out-of-band that you indeed lost your key.> > If you are the only signer and you lost your key, then you basically lose "admin"> > access to the project.> > > > > * What should happen in the case of diverging histories? I.e. if one subset of> > > maintainers sign one history and another a different history, do we not end up> > > with all the same UX problems you currently have with peer IDs?> > > > This would basically require maintainers to equivocate, or "double sign", unless> > you set your threshold to a sub-majority. Most probably this is done maliciously> > and it will be easy to see who has signed both histories. I'm not sure there is any> > difference between the two systems when it concerns diverging histories, is there?> > > Would this not be quite likely to happen in a multi-device single-key> world? If I make some changes on my laptop and push and then also make> some changes on my desktop and push then you now have a diverged history> no?
Well, in that case wouldn't one of the pushes fail? ie. git will tell you that you
have to pull first, and then you'd get a local conflict you'd have to fix.
In the case of COBs you wouldn't fail to push/sync but I'd expect the CRDT to handle
the conflict..
On 05/08/22 01:13pm, Alexis Sellier wrote:
> > > > * What should happen in the case of diverging histories? I.e. if one subset of> > > > maintainers sign one history and another a different history, do we not end up> > > > with all the same UX problems you currently have with peer IDs?> > >>> > > This would basically require maintainers to equivocate, or "double sign", unless> > > you set your threshold to a sub-majority. Most probably this is done maliciously> > > and it will be easy to see who has signed both histories. I'm not sure there is any> > > difference between the two systems when it concerns diverging histories, is there?> >>> >>> > Would this not be quite likely to happen in a multi-device single-key> > world? If I make some changes on my laptop and push and then also make> > some changes on my desktop and push then you now have a diverged history> > no?>> Well, in that case wouldn't one of the pushes fail? ie. git will tell you that you> have to pull first, and then you'd get a local conflict you'd have to fix.
That's only true if you're pushing to the same server though right? This
means that if your one true server is offline (or blocked by your ISP)
then you can't push. If you want a network model where you can announce
changes to any connected peer (or maybe to a subset, i.e. public seeds)
then I think you have to allow for conflicts.
Yeah, that's a good point. I'm trying to think of the cost/benefit here. The advantage
of the key-per-device model is also a disadvantage in that a user needs one repository/remote
per device, ie. it makes it harder to share code with themselves, which is counter-intuitive.
I think this needs more thought, and I'm definitely not against giving users the choice here
in having an identity backed by more than one key, as long as there's an alternative path
for single-device users which doesn't impose all that complexity.
This implies that the identifier format should be future-compatible though, to support things
other than keys :)
------- Original Message -------
On Friday, August 5th, 2022 at 15:37, Alex Good <alex@memoryandthought.me> wrote:
> > > On 05/08/22 01:13pm, Alexis Sellier wrote:> > > > > > * What should happen in the case of diverging histories? I.e. if one subset of> > > > > maintainers sign one history and another a different history, do we not end up> > > > > with all the same UX problems you currently have with peer IDs?> > > > > > This would basically require maintainers to equivocate, or "double sign", unless> > > > you set your threshold to a sub-majority. Most probably this is done maliciously> > > > and it will be easy to see who has signed both histories. I'm not sure there is any> > > > difference between the two systems when it concerns diverging histories, is there?> > > > > Would this not be quite likely to happen in a multi-device single-key> > > world? If I make some changes on my laptop and push and then also make> > > some changes on my desktop and push then you now have a diverged history> > > no?> > > > Well, in that case wouldn't one of the pushes fail? ie. git will tell you that you> > have to pull first, and then you'd get a local conflict you'd have to fix.> > > That's only true if you're pushing to the same server though right? This> means that if your one true server is offline (or blocked by your ISP)> then you can't push. If you want a network model where you can announce> changes to any connected peer (or maybe to a subset, i.e. public seeds)> then I think you have to allow for conflicts.