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 git2 as raw;
pub use git_ref_format as fmt; pub use git_ref_format as fmt;
pub use git_ref_format::{ 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 radicle_git_ext as ext;
pub use storage::git::transport::local::Url; pub use storage::git::transport::local::Url;
@ -59,9 +59,6 @@ pub enum ListRefsError {
pub mod refs { pub mod refs {
use super::*; 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. /// Try to get a qualified reference from a generic reference.
pub fn qualified_from<'a>(r: &'a git2::Reference) -> Result<(Qualified<'a>, Oid), RefError> { pub fn qualified_from<'a>(r: &'a git2::Reference) -> Result<(Qualified<'a>, Oid), RefError> {
let name = r.name().ok_or(RefError::InvalidName)?; let name = r.name().ok_or(RefError::InvalidName)?;
@ -78,17 +75,36 @@ pub mod refs {
pub mod storage { pub mod storage {
use super::*; 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. /// Create the [`Namespaced`] `branch` under the `remote` namespace, i.e.
///
/// `refs/namespaces/<remote>/refs/heads/<branch>` /// `refs/namespaces/<remote>/refs/heads/<branch>`
///
pub fn branch<'a>(remote: &RemoteId, branch: &RefStr) -> Namespaced<'a> { pub fn branch<'a>(remote: &RemoteId, branch: &RefStr) -> Namespaced<'a> {
Qualified::from(git_ref_format::lit::refs_heads(branch)).with_namespace(remote.into()) 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 { 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)] #[derive(Clone, Copy, Debug)]
pub struct Trusted; pub struct Trusted;
/// Path to the identity document in the identity branch.
pub static PATH: Lazy<&Path> = Lazy::new(|| Path::new("radicle.json")); 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; pub const MAX_STRING_LENGTH: usize = 255;
/// Maximum number of a delegates in the identity document.
pub const MAX_DELEGATES: usize = 255; pub const MAX_DELEGATES: usize = 255;
#[derive(Error, Debug)] #[derive(Error, Debug)]
@ -148,11 +150,6 @@ impl Doc<Verified> {
msg: &str, msg: &str,
storage: &S, storage: &S,
) -> Result<(Id, git::Oid, S::Repository), DocError> { ) -> 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 (doc_oid, doc) = self.encode()?;
let id = Id::from(doc_oid); let id = Id::from(doc_oid);
let repo = storage.repository(id)?; let repo = storage.repository(id)?;
@ -358,8 +355,8 @@ impl Doc<Unverified> {
impl<V> Doc<V> { impl<V> Doc<V> {
pub fn head<R: ReadRepository>(remote: &RemoteId, repo: &R) -> Result<Oid, DocError> { 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, &git::refs::storage::IDENTITY_BRANCH)
repo.reference_oid(remote, &head).map_err(DocError::from) .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: // Creates or copies the following references:
// //
// refs/remotes/<pk>/heads/master // refs/remotes/<pk>/heads/master
// refs/remotes/<pk>/heads/radicle/id // refs/remotes/<pk>/rad/id
// refs/remotes/<pk>/tags/* // refs/remotes/<pk>/tags/*
// refs/remotes/<pk>/rad/signature // refs/remotes/<pk>/rad/signature

View File

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

View File

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