Move `radicle/id` and `radicle/signature`

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>
This commit is contained in:
Alexis Sellier 2022-10-29 11:53:10 +02:00
parent 25c982cd8c
commit 16b22d9178
No known key found for this signature in database
6 changed files with 59 additions and 49 deletions

View File

@ -19,7 +19,7 @@ pub use ext::Oid;
pub use git2 as raw;
pub use git_ref_format as fmt;
pub use git_ref_format::{
lit, name, qualified, refname, Component, Namespaced, Qualified, RefStr, RefString,
component, lit, name, qualified, refname, Component, Namespaced, Qualified, RefStr, RefString,
};
pub use radicle_git_ext as ext;
pub use storage::git::transport::local::Url;
@ -59,9 +59,6 @@ pub enum ListRefsError {
pub mod refs {
use super::*;
/// Where project information is kept.
pub static IDENTITY_BRANCH: Lazy<RefString> = Lazy::new(|| refname!("radicle/id"));
/// Try to get a qualified reference from a generic reference.
pub fn qualified_from<'a>(r: &'a git2::Reference) -> Result<(Qualified<'a>, Oid), RefError> {
let name = r.name().ok_or(RefError::InvalidName)?;
@ -78,17 +75,36 @@ pub mod refs {
pub mod storage {
use super::*;
/// Where the project's identity document is stored.
///
/// `refs/rad/id`
///
pub static IDENTITY_BRANCH: Lazy<Qualified> = Lazy::new(|| {
Qualified::from_components(name::component!("rad"), name::component!("id"), None)
});
/// Where the project's signed references are stored.
///
/// `refs/rad/sigrefs`
///
pub static SIGREFS_BRANCH: Lazy<Qualified> = Lazy::new(|| {
Qualified::from_components(name::component!("rad"), name::component!("sigrefs"), None)
});
/// Create the [`Namespaced`] `branch` under the `remote` namespace, i.e.
///
/// `refs/namespaces/<remote>/refs/heads/<branch>`
///
pub fn branch<'a>(remote: &RemoteId, branch: &RefStr) -> Namespaced<'a> {
Qualified::from(git_ref_format::lit::refs_heads(branch)).with_namespace(remote.into())
}
/// Get the branch used to track project information.
/// Get the branch where the project's identity document is stored.
///
/// `refs/namespaces/<remote>/refs/rad/id`
///
/// `refs/namespaces/<remote>/refs/heads/radicle/id`
pub fn id(remote: &RemoteId) -> Namespaced {
branch(remote, &IDENTITY_BRANCH)
IDENTITY_BRANCH.with_namespace(remote.into())
}
}

View File

@ -31,9 +31,11 @@ pub struct Untrusted;
#[derive(Clone, Copy, Debug)]
pub struct Trusted;
/// Path to the identity document in the identity branch.
pub static PATH: Lazy<&Path> = Lazy::new(|| Path::new("radicle.json"));
/// Maximum length of a string in the identity document.
pub const MAX_STRING_LENGTH: usize = 255;
/// Maximum number of a delegates in the identity document.
pub const MAX_DELEGATES: usize = 255;
#[derive(Error, Debug)]
@ -148,11 +150,6 @@ impl Doc<Verified> {
msg: &str,
storage: &S,
) -> Result<(Id, git::Oid, S::Repository), DocError> {
// You can checkout this branch in your working copy with:
//
// git fetch rad
// git checkout -b radicle/id remotes/rad/radicle/id
//
let (doc_oid, doc) = self.encode()?;
let id = Id::from(doc_oid);
let repo = storage.repository(id)?;
@ -358,8 +355,8 @@ impl Doc<Unverified> {
impl<V> Doc<V> {
pub fn head<R: ReadRepository>(remote: &RemoteId, repo: &R) -> Result<Oid, DocError> {
let head = git::Qualified::from(git::lit::refs_heads(&*git::refs::IDENTITY_BRANCH));
repo.reference_oid(remote, &head).map_err(DocError::from)
repo.reference_oid(remote, &git::refs::storage::IDENTITY_BRANCH)
.map_err(DocError::from)
}
}

View File

@ -122,7 +122,7 @@ pub fn fork_remote<G: Signer, S: storage::WriteStorage>(
// Creates or copies the following references:
//
// refs/remotes/<pk>/heads/master
// refs/remotes/<pk>/heads/radicle/id
// refs/remotes/<pk>/rad/id
// refs/remotes/<pk>/tags/*
// refs/remotes/<pk>/rad/signature

View File

@ -24,10 +24,10 @@ pub use crate::git::*;
use super::{Namespaces, RefUpdate, RemoteId};
use transport::remote;
pub static REMOTES_GLOB: Lazy<refspec::PatternString> =
pub static NAMESPACES_GLOB: Lazy<refspec::PatternString> =
Lazy::new(|| refspec::pattern!("refs/namespaces/*"));
pub static SIGNATURES_GLOB: Lazy<refspec::PatternString> =
Lazy::new(|| refspec::pattern!("refs/namespaces/*/radicle/signature"));
pub static SIGREFS_GLOB: Lazy<refspec::PatternString> =
Lazy::new(|| refspec::pattern!("refs/namespaces/*/rad/sigrefs"));
// TODO: Is this is the wrong place for this type?
#[derive(Error, Debug)]
@ -309,7 +309,7 @@ impl Repository {
pub fn remote_ids(
&self,
) -> Result<impl Iterator<Item = Result<RemoteId, refs::Error>> + '_, git2::Error> {
let iter = self.backend.references_glob(SIGNATURES_GLOB.as_str())?.map(
let iter = self.backend.references_glob(SIGREFS_GLOB.as_str())?.map(
|reference| -> Result<RemoteId, refs::Error> {
let r = reference?;
let name = r.name().ok_or(refs::Error::InvalidRef)?;
@ -327,16 +327,17 @@ impl Repository {
impl Iterator<Item = Result<(RemoteId, Remote<Verified>), refs::Error>> + '_,
git2::Error,
> {
let remotes = self.backend.references_glob(SIGNATURES_GLOB.as_str())?.map(
|reference| -> Result<_, _> {
let r = reference?;
let name = r.name().ok_or(refs::Error::InvalidRef)?;
let (id, _) = git::parse_ref_namespaced::<RemoteId>(name)?;
let remote = self.remote(&id)?;
let remotes =
self.backend
.references_glob(SIGREFS_GLOB.as_str())?
.map(|reference| -> Result<_, _> {
let r = reference?;
let name = r.name().ok_or(refs::Error::InvalidRef)?;
let (id, _) = git::parse_ref_namespaced::<RemoteId>(name)?;
let remote = self.remote(&id)?;
Ok((id, remote))
},
);
Ok((id, remote))
});
Ok(remotes)
}
@ -358,7 +359,7 @@ impl Repository {
return Ok(None);
};
if refname == *refs::SIGNATURE_REF {
if refname == *refs::SIGREFS_BRANCH {
// Ignore the signed-refs reference, as this is what we're verifying.
return Ok(None);
}
@ -714,7 +715,7 @@ mod tests {
use crate::assert_matches;
use crate::git;
use crate::rad;
use crate::storage::refs::SIGNATURE_REF;
use crate::storage::refs::SIGREFS_BRANCH;
use crate::storage::{ReadRepository, ReadStorage, RefUpdate, WriteRepository};
use crate::test::arbitrary;
use crate::test::fixtures;
@ -733,7 +734,7 @@ mod tests {
// Strip the remote refs of sigrefs so we can compare them.
for remote in refs.values_mut() {
let sigref = (*SIGNATURE_REF).to_ref_string();
let sigref = (*SIGREFS_BRANCH).to_ref_string();
remote.remove(&sigref).unwrap();
}
@ -866,7 +867,7 @@ mod tests {
.collect::<Vec<_>>();
refs.sort();
assert_eq!(refs, vec!["refs/heads/master", "refs/heads/radicle/id"]);
assert_eq!(refs, vec!["refs/heads/master", "refs/rad/id"]);
}
#[test]
@ -972,8 +973,8 @@ mod tests {
updates,
vec![
format!("refs/namespaces/{remote}/refs/heads/master"),
format!("refs/namespaces/{remote}/refs/heads/radicle/id"),
format!("refs/namespaces/{remote}/refs/radicle/signature")
format!("refs/namespaces/{remote}/refs/rad/id"),
format!("refs/namespaces/{remote}/refs/rad/sigrefs")
]
);
}
@ -1005,7 +1006,7 @@ mod tests {
let mut unsigned = project.references(&alice).unwrap();
// The signed refs doesn't contain the signature ref itself.
let sigref = (*SIGNATURE_REF).to_ref_string();
let sigref = (*SIGREFS_BRANCH).to_ref_string();
unsigned.remove(&sigref).unwrap();
assert_eq!(remote.refs, signed);

View File

@ -8,23 +8,19 @@ use std::path::Path;
use std::str::FromStr;
use crypto::{PublicKey, Signature, Signer, Unverified, Verified};
use once_cell::sync::Lazy;
use radicle_git_ext as git_ext;
use thiserror::Error;
use crate::git;
use crate::git::ext as git_ext;
use crate::git::Oid;
use crate::storage;
use crate::storage::{ReadRepository, RemoteId, WriteRepository};
pub static SIGNATURE_REF: Lazy<git::Qualified> = Lazy::new(|| {
git::Qualified::from_components(
git::name::component!("radicle"),
git::name::component!("signature"),
None,
)
});
pub use crate::git::refs::storage::*;
/// File in which the signed references are stored, in the `refs/rad/sigrefs` branch.
pub const REFS_BLOB_PATH: &str = "refs";
/// File in which the signature over the references is stored in the `refs/rad/sigrefs` branch.
pub const SIGNATURE_BLOB_PATH: &str = "signature";
#[derive(Debug)]
@ -129,7 +125,7 @@ impl Refs {
let mut buf = String::new();
let refs = self
.iter()
.filter(|(name, oid)| name.as_refstr() != (*SIGNATURE_REF).as_ref() && !oid.is_zero());
.filter(|(name, oid)| name.as_refstr() != SIGREFS_BRANCH.as_ref() && !oid.is_zero());
for (name, oid) in refs {
buf.push_str(&oid.to_string());
@ -231,7 +227,7 @@ impl SignedRefs<Verified> {
where
S: ReadRepository,
{
let oid = repo.reference_oid(remote, &SIGNATURE_REF)?;
let oid = repo.reference_oid(remote, &SIGREFS_BRANCH)?;
SignedRefs::load_at(oid, remote, repo)
}
@ -266,7 +262,7 @@ impl SignedRefs<Verified> {
remote: &RemoteId,
repo: &S,
) -> Result<Updated, Error> {
let sigref = &*SIGNATURE_REF;
let sigref = &SIGREFS_BRANCH;
let parent = match repo.reference(remote, sigref) {
Ok(r) => Some(r.peel_to_commit()?),
Err(git_ext::Error::Git(e)) if git_ext::is_not_found_err(&e) => None,

View File

@ -152,7 +152,7 @@ impl Arbitrary for Refs {
"heads/feature/1",
"heads/feature/2",
"heads/feature/3",
"heads/radicle/id",
"rad/id",
"tags/v1.0",
"tags/v2.0",
"notes/1",