Make the validation logic customisable by extracting it out into a
separate trait that can be defined by other crates.
The Repository validation logic stays the same.
Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
If a `rad` command that requires an RID is executed within a
subdirectory of a Radicle project, then it will fail saying:
✗ Error: Current directory is not a radicle project
Improve this flow by searching parent directories and/or using the
GIT_DIR environment variable.
This is safe as long as the operations are read-only when calling
`cwd`. Currently they are:
- `Repository::open_ext` -- will not create a repository, only open
one.
- `Repository::find_remote` -- this will only read the remote from the
config and get the URL to parse the RID.
Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
Introduces a new COB type to store repository identity documents.
The reason for this change is to:
1. Simplify the code, as the identity document logic resembled a COB,
yet it had custom logic. This allows existing COB code to be used for
identities.
2. Make identity document update logic more flexible, since COB actions
can be added in the future.
3. Re-purpose existing tools around COBs to work on identities, eg. `rad
cob`.
4. Unify the concept of an identity change proposal, with regular identity
changes. This means we can remove the `id.proposal` COB in favor of
using the `id` COB itself.
Notes
-----
* Each repository has one Identity COB.
* The `Proposal` COB has been repurposed into the `Identity` COB.
* Identity documents are stored as *embeds* inside the Identity COB
actions.
* The action that contains new document versions is called `revision`,
just like the Patches COB.
* The namespaced `rad/id` ref is a symbolic reference to that Identity
COB.
* The canonical `rad/id` ref is a direct reference to the commit in the
Identity COB that contains the latest *accepted* revision of the
document.
* All commands for managing identities have been folded into `rad id`.
Hence `rad delegate` and `rad edit` are removed.
* The concept of "rebasing" an identity document is gone.
* The `rad id` output has been updated to match the style of other
commands.
* When a revision has enough signatures, it is automatically adopted as
the current identity, there is no longer the need for a "commit"
action.
* When an identity revision is proposed, and the current identity has a
threshold of `1`, that identity is automatically accepted due to the
above point.
* The idea of "verifying a peer's identity branch" no longer applies, as
COBs cannot be verified one history at a time.
* Since the root commit of the Identity COB does not have a "Resource"
to point to (it would have to point to itself, which is impossible),
we've made the resource id optional for COBs.
Sets the current branch's upstream to point to the given patch.
This allows for pushes to update the patch.
When opening a patch, if the current branch already has an upstream,
it isn't updated automatically. This is why this command exists.
Private repos are implemented by extending the identity document with a
`visibility` attribute, that can either be `"public"` (default) or
`"private"`.
In case of `private` visibility, only the delegates are allowed to view
the repo, as well as any DIDs added to the allow list.
To implement repo visibility, we simply block fetches from and
announcements to peers for whom the repo should remain invisible.
Private repos are also not announced in the `inventory` message, since
the full list of peers that *may* have the repo is retrievable from the
repo identity. This could cause errors if eg. a peer who is allowed to
view the repo doesn't actually have it. However this is an ok trade-off
for now to keep the complexity low. For repos to truly be private, it's
important that the RIDs don't leak either.
Finally, we modify `radicle-httpd` for now to only list public repos.
Eventually, we would want to change this depending on whether an allowed
peer is authenticated with the service or not.
---
It's also worth mentioning why this approach was taken, vs. end-to-end
encryption. The reasons are as follows:
1. Nodes that do not have access to a private repo will generally not want to
replicate encrypted data that they cannot examine or use.
2. The chosen solution is trivial, while encrypting git objects isn't.
3. Performance of the chosen solution is much better, there is no
overhead.
4. Privacy of the chosen solution is better: RIDs are never leaked, and
neither is the existence of a private repo, nor who has access to it.
There is one downside: Paying for storage of private repos is no better
in terms of privacy than what GitHub offers. Hosting providers will have
access to your private repos, if this solution is used.
This new trait is used when only signing refs is needed, and not general
write access to a repository.
We also implement `ReadRepository` and `SignRepository` for
`DraftStore`.
Remove this command in favor of the `git push` flow.
We also remove the `rad/patches` remote configuration which wasn't
working properly with `git fetch --all`.
When applying a `Merge` action, we verify that the commit is in the
history of the default branch of that user.
Since this is not the case when issuing a `rad merge`, and since that
command is no longer needed with the push-based merge, we remove the
`rad merge` command completely.
This adds the ability to the git-remote-helper to open and update
patches via a `git push` to the magic ref `refs/patches` and
`refs/heads/patches/<patch-id>`.
The main change is that we had to move away from offering the `connect`
capability in the remote helper, to offering `push` and `fetch`
individually.
To get a feel for how this works, see the `rad-patch-via-push.md`
example.
If the 'rad' remote is still in the git config, then some of the CLI
tooling will think the project exists -- even after running `rad rm`.
For example, in the current state, if `rad rm` is followed by `rad
init` then the operation will fail.
During `rad rm`, attempt to delete the 'rad' remote.
Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
Before this change, the identity document would be loaded for the
COB signer. This meant that a fork would be needed for that signer.
After this change, it's no longer necessary, since the identity doc
head is computed from available remotes.
While making those changes, it was also apparent that some of the
identity-related functions had bad names and error types, this
was fixed as well.
The `validate` method of `Project` was unused, which is problematic if
the attributes are supposed to be validated based on some
constraints. The issue is that `Project` provided public construction
of its fields with enforcing validation.
This change makes `Project`'s attributes private and introduces a
smart constructor `new` which is fallible if any of the constraints
are not met. The error type was changed to be a vector of errors since
all of these errors can be collected for better error reporting.
Deserialization also provided a way of constructing a `Project`
without ensuring any of the constraints were checked. To prevent this
a hand-rolled `Deserialize` is provided that goes through
`Project::new`.
To access the fields of `Project`, accessor functions are added and
all call sites are updated to use them.
Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
In RIP-2, we specify that identity document root commits must include
the signature of all founding delegates.
This commit adds the required signatures during document creation
and verifies them on load.
Signed-off-by: Alexis Sellier <alexis@radicle.xyz>
The new hierarchy should be much more correct, and cleaner:
* `identity` (`Identity`)
* `identity::did` (`Did`)
* `identity::doc` (`Doc`, `Payload`)
* `identity::doc::id` (`Id`)
* `identity::project` (`Project`)
Signed-off-by: Alexis Sellier <alexis@radicle.xyz>
The tracking command was tracking a project when it should
have been tracking peers.
We also add the ability to pass an alias when tracking from
the CLI.
Signed-off-by: Alexis Sellier <alexis@radicle.xyz>
We are working on other mechanisms to help identify keys, and this
is just redundant.
Also update some of the CLI examples to create a canonical example
for documentation.
Signed-off-by: Alexis Sellier <alexis@radicle.xyz>
To support ssh-agent, add a signing method that can fail.
Also cleanup usage so that we always accept signer references.
Signed-off-by: Alexis Sellier <alexis@radicle.xyz>
We move the identity branch out of `heads/` and to the old location:
refs/rad/id
We move the signed refs branch to:
refs/rad/sigrefs
Keeping both "special" branches under the same hierarchy makes things a
bit easier to work with, and tells the user that they should be updated
with special tooling.
We also revert to `rad/` because we no longer have the issue of having
`rad/rad/id` when doing a checkout of the remote branch in a working
copy.
Signed-off-by: Alexis Sellier <alexis@radicle.xyz>
The crypto types are useful to use in other components that are
separate from the radicle crate, e.g. the incoming radicle-cobs
crate.
Separate out the types into a radicle-crypto crate. This crate defines
the usual PublicKey, SecretKey, and Signature types. It also provides
the ssh functionality, under the `ssh` feature. It is also necessary
to provide the `From` impl for `Component` here, which again is
guarded by the `git-ref-format` feature.
The `Arbitrary` implementation are moved. The arbitrary decision of
redefining `ByteArray` in both radicle-crypto and radicle was made.
Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
The changes in this commit are all intertwined and it was hard to
split them into smaller commits:
* Use custom transports everywhere
Instead of `file://` and instead of using a child process for fetching
and pushing; we go through our custom transports, which use the `rad://`
and `heartwood://` schemes.
* Introduce a 'mock' remote transport
To test the remote transport without needing to spawn TCP streams,
we add a mock transport that works between storages on the file
system.
* Get rid of node's `git-url`
Instead of git urls, nodes simply use their node-ids to replicate.
Since the `HEAD` reference is trusted (we set it locally), use that
when possible, instead of re-computing it.
Signed-off-by: Alexis Sellier <alexis@radicle.xyz>