radicle/sigrefs: Use `SignedRefsAt` everywhere

To make more information available to callers, prefer returning
`SignedRefsAt` everywhere.
This commit is contained in:
Lorenz Leutgeb 2026-03-24 21:23:05 +01:00 committed by Fintan Halpenny
parent d25fb7f672
commit 07011233eb
9 changed files with 35 additions and 39 deletions

View File

@ -23,7 +23,7 @@ pub mod error {
pub(crate) fn validate( pub(crate) fn validate(
repo: &impl ValidateRepository, repo: &impl ValidateRepository,
SignedRefsAt { sigrefs, .. }: SignedRefsAt, sigrefs: SignedRefsAt,
) -> Result<Option<Validations>, radicle::storage::Error> { ) -> Result<Option<Validations>, radicle::storage::Error> {
let remote = radicle::storage::Remote::new(sigrefs); let remote = radicle::storage::Remote::new(sigrefs);
let validations = repo.validate_remote(&remote)?; let validations = repo.validate_remote(&remote)?;

View File

@ -799,7 +799,7 @@ where
// with it. // with it.
fn validate_remote(&self, remote: &Remote) -> Result<Validations, storage::Error> { fn validate_remote(&self, remote: &Remote) -> Result<Validations, storage::Error> {
// Contains a copy of the signed refs of this remote. // Contains a copy of the signed refs of this remote.
let mut signed = BTreeMap::from((*remote.refs).clone()); let mut signed = BTreeMap::from((*remote.refs.sigrefs).clone());
let mut validations = Validations::default(); let mut validations = Validations::default();
let mut has_sigrefs = false; let mut has_sigrefs = false;

View File

@ -15,7 +15,7 @@ use crate::identity::project::{Project, ProjectName};
use crate::node::device::Device; use crate::node::device::Device;
use crate::storage::git::transport; use crate::storage::git::transport;
use crate::storage::git::Repository; use crate::storage::git::Repository;
use crate::storage::refs::SignedRefs; use crate::storage::refs::SignedRefsAt;
use crate::storage::RepositoryError; use crate::storage::RepositoryError;
use crate::storage::{ReadRepository as _, RemoteId, SignRepository as _}; use crate::storage::{ReadRepository as _, RemoteId, SignRepository as _};
use crate::storage::{WriteRepository, WriteStorage}; use crate::storage::{WriteRepository, WriteStorage};
@ -55,7 +55,7 @@ pub fn init<G, S>(
visibility: Visibility, visibility: Visibility,
signer: &Device<G>, signer: &Device<G>,
storage: S, storage: S,
) -> Result<(RepoId, identity::Doc, SignedRefs), InitError> ) -> Result<(RepoId, identity::Doc, SignedRefsAt), InitError>
where where
G: crypto::signature::Signer<crypto::Signature>, G: crypto::signature::Signer<crypto::Signature>,
S: WriteStorage, S: WriteStorage,
@ -102,7 +102,7 @@ fn init_configure<G>(
url: &git::Url, url: &git::Url,
identity: git::Oid, identity: git::Oid,
signer: &Device<G>, signer: &Device<G>,
) -> Result<SignedRefs, InitError> ) -> Result<SignedRefsAt, InitError>
where where
G: crypto::signature::Signer<crypto::Signature>, G: crypto::signature::Signer<crypto::Signature>,
{ {

View File

@ -28,7 +28,7 @@ use crate::node::SyncedAt;
use crate::storage::git::NAMESPACES_GLOB; use crate::storage::git::NAMESPACES_GLOB;
use crate::storage::refs::{FeatureLevel, Refs, SignedRefsAt}; use crate::storage::refs::{FeatureLevel, Refs, SignedRefsAt};
use self::refs::{RefsAt, SignedRefs}; use self::refs::RefsAt;
use crate::git::UserInfo; use crate::git::UserInfo;
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
@ -385,12 +385,12 @@ impl IntoIterator for Remotes {
} }
} }
impl From<Remotes> for RandomMap<RemoteId, Refs> { impl From<Remotes> for RandomMap<RemoteId, SignedRefsAt> {
fn from(other: Remotes) -> Self { fn from(other: Remotes) -> Self {
let mut remotes = RandomMap::with_hasher(fastrand::Rng::new().into()); let mut remotes = RandomMap::with_hasher(fastrand::Rng::new().into());
for (k, v) in other.into_iter() { for (k, v) in other.into_iter() {
remotes.insert(k, v.refs.into()); remotes.insert(k, v.refs);
} }
remotes remotes
} }
@ -401,12 +401,12 @@ impl From<Remotes> for RandomMap<RemoteId, Refs> {
pub struct Remote { pub struct Remote {
/// Git references published under this remote, and their hashes. /// Git references published under this remote, and their hashes.
#[serde(flatten)] #[serde(flatten)]
pub refs: SignedRefs, pub refs: SignedRefsAt,
} }
impl Remote { impl Remote {
/// Create a new remotes object. /// Create a new remotes object.
pub fn new(refs: impl Into<SignedRefs>) -> Self { pub fn new(refs: impl Into<SignedRefsAt>) -> Self {
Self { refs: refs.into() } Self { refs: refs.into() }
} }
@ -428,7 +428,7 @@ impl Remote {
} }
impl Deref for Remote { impl Deref for Remote {
type Target = SignedRefs; type Target = SignedRefsAt;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.refs &self.refs
@ -697,14 +697,14 @@ pub trait WriteRepository: ReadRepository + SignRepository {
/// Allows signing refs. /// Allows signing refs.
pub trait SignRepository { pub trait SignRepository {
/// Sign the repository's refs under the `refs/rad/sigrefs` branch. /// Sign the repository's refs under the `refs/rad/sigrefs` branch.
fn sign_refs<G>(&self, signer: &Device<G>) -> Result<SignedRefs, RepositoryError> fn sign_refs<G>(&self, signer: &Device<G>) -> Result<SignedRefsAt, RepositoryError>
where where
G: crypto::signature::Signer<crypto::Signature>; G: crypto::signature::Signer<crypto::Signature>;
/// Sign the repository's refs under the `refs/rad/sigrefs` branch, even if unchanged. /// Sign the repository's refs under the `refs/rad/sigrefs` branch, even if unchanged.
/// ///
/// Most users will prefer [`Self::sign_refs`]. /// Most users will prefer [`Self::sign_refs`].
fn force_sign_refs<G>(&self, signer: &Device<G>) -> Result<SignedRefs, RepositoryError> fn force_sign_refs<G>(&self, signer: &Device<G>) -> Result<SignedRefsAt, RepositoryError>
where where
G: crypto::signature::Signer<crypto::Signature>; G: crypto::signature::Signer<crypto::Signature>;
} }

View File

@ -18,7 +18,7 @@ use crate::identity::doc::DocError;
use crate::identity::{CanonicalRefs, Doc, DocAt, RepoId}; use crate::identity::{CanonicalRefs, Doc, DocAt, RepoId};
use crate::identity::{Identity, Project}; use crate::identity::{Identity, Project};
use crate::node::device::Device; use crate::node::device::Device;
use crate::storage::refs::{FeatureLevel, Refs, SignedRefs, SignedRefsAt}; use crate::storage::refs::{FeatureLevel, Refs, SignedRefsAt};
use crate::storage::{refs, SignedRefsInfo}; use crate::storage::{refs, SignedRefsInfo};
use crate::storage::{ use crate::storage::{
ReadRepository, ReadStorage, Remote, Remotes, RepositoryInfo, SetHead, SignRepository, ReadRepository, ReadStorage, Remote, Remotes, RepositoryInfo, SetHead, SignRepository,
@ -631,7 +631,12 @@ impl RemoteRepository for Repository {
} }
fn remote(&self, remote: &RemoteId) -> Result<Remote, refs::Error> { fn remote(&self, remote: &RemoteId) -> Result<Remote, refs::Error> {
let refs = SignedRefs::load(*remote, self)?; let refs = SignedRefsAt::load(*remote, self)?;
let refs = refs.ok_or_else(|| {
refs::Error::Read(refs::sigrefs::read::error::Read::MissingSigrefs {
namespace: *remote,
})
})?;
Ok(Remote::new(refs)) Ok(Remote::new(refs))
} }
@ -651,7 +656,7 @@ impl RemoteRepository for Repository {
impl ValidateRepository for Repository { impl ValidateRepository for Repository {
fn validate_remote(&self, remote: &Remote) -> Result<Validations, Error> { fn validate_remote(&self, remote: &Remote) -> Result<Validations, Error> {
// Contains a copy of the signed refs of this remote. // Contains a copy of the signed refs of this remote.
let mut signed = BTreeMap::from((*remote.refs).clone()); let mut signed = BTreeMap::from((*remote.refs.sigrefs).clone());
let mut failures = Validations::default(); let mut failures = Validations::default();
let mut has_sigrefs = false; let mut has_sigrefs = false;
@ -1002,14 +1007,14 @@ impl SignRepository for Repository {
fn sign_refs<G: crypto::signature::Signer<crypto::Signature>>( fn sign_refs<G: crypto::signature::Signer<crypto::Signature>>(
&self, &self,
signer: &Device<G>, signer: &Device<G>,
) -> Result<SignedRefs, RepositoryError> { ) -> Result<SignedRefsAt, RepositoryError> {
self.sign_refs_with(signer, false) self.sign_refs_with(signer, false)
} }
fn force_sign_refs<G: crypto::signature::Signer<crypto::Signature>>( fn force_sign_refs<G: crypto::signature::Signer<crypto::Signature>>(
&self, &self,
signer: &Device<G>, signer: &Device<G>,
) -> Result<SignedRefs, RepositoryError> { ) -> Result<SignedRefsAt, RepositoryError> {
self.sign_refs_with(signer, true) self.sign_refs_with(signer, true)
} }
} }
@ -1019,7 +1024,7 @@ impl Repository {
&self, &self,
signer: &Device<G>, signer: &Device<G>,
force: bool, force: bool,
) -> Result<SignedRefs, RepositoryError> { ) -> Result<SignedRefsAt, RepositoryError> {
let remote = signer.public_key(); let remote = signer.public_key();
// Ensure the root reference is set, which is checked during sigref verification. // Ensure the root reference is set, which is checked during sigref verification.
if self if self
@ -1038,7 +1043,7 @@ impl Repository {
refs.save(*remote, committer, self, signer)? refs.save(*remote, committer, self, signer)?
}; };
Ok(signed.sigrefs) Ok(signed)
} }
} }
@ -1224,6 +1229,6 @@ mod tests {
unsigned.remove_sigrefs().unwrap(); unsigned.remove_sigrefs().unwrap();
assert_eq!(remote.refs.refs(), signed.refs()); assert_eq!(remote.refs.refs(), signed.refs());
assert_eq!(*remote.refs, unsigned); assert_eq!(*remote.refs.refs(), unsigned);
} }
} }

View File

@ -239,7 +239,7 @@ where
fn sign_refs<G: crypto::signature::Signer<crypto::Signature>>( fn sign_refs<G: crypto::signature::Signer<crypto::Signature>>(
&self, &self,
signer: &Device<G>, signer: &Device<G>,
) -> Result<storage::refs::SignedRefs, RepositoryError> { ) -> Result<storage::refs::SignedRefsAt, RepositoryError> {
// Since this is a draft store, we do not actually want to sign the refs. // Since this is a draft store, we do not actually want to sign the refs.
// Instead, we just return the existing signed refs. // Instead, we just return the existing signed refs.
let remote = self.repo.remote(signer.public_key())?; let remote = self.repo.remote(signer.public_key())?;
@ -250,7 +250,7 @@ where
fn force_sign_refs<G: crypto::signature::Signer<crypto::Signature>>( fn force_sign_refs<G: crypto::signature::Signer<crypto::Signature>>(
&self, &self,
signer: &Device<G>, signer: &Device<G>,
) -> Result<storage::refs::SignedRefs, RepositoryError> { ) -> Result<storage::refs::SignedRefsAt, RepositoryError> {
self.sign_refs(signer) self.sign_refs(signer)
} }
} }

View File

@ -471,7 +471,7 @@ impl std::fmt::Display for RefsAt {
/// Verified [`SignedRefs`] that keeps track of their content address /// Verified [`SignedRefs`] that keeps track of their content address
/// [`Oid`]. /// [`Oid`].
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct SignedRefsAt { pub struct SignedRefsAt {
pub sigrefs: SignedRefs, pub sigrefs: SignedRefs,
pub at: Oid, pub at: Oid,

View File

@ -10,7 +10,7 @@ use crate::node::Alias;
use crate::rad; use crate::rad;
use crate::storage::git::transport; use crate::storage::git::transport;
use crate::storage::git::Storage; use crate::storage::git::Storage;
use crate::storage::refs::SignedRefs; use crate::storage::refs::SignedRefsAt;
/// The birth of the radicle project, January 1st, 2018. /// The birth of the radicle project, January 1st, 2018.
pub const RADICLE_EPOCH: i64 = 1514817556; pub const RADICLE_EPOCH: i64 = 1514817556;
@ -72,7 +72,7 @@ pub fn project<P, G>(
path: P, path: P,
storage: &Storage, storage: &Storage,
signer: &Device<G>, signer: &Device<G>,
) -> Result<(RepoId, SignedRefs, git::raw::Repository, git::raw::Oid), rad::InitError> ) -> Result<(RepoId, SignedRefsAt, git::raw::Repository, git::raw::Oid), rad::InitError>
where where
P: AsRef<Path>, P: AsRef<Path>,
G: crypto::signature::Signer<crypto::Signature>, G: crypto::signature::Signer<crypto::Signature>,

View File

@ -181,9 +181,7 @@ impl RemoteRepository for MockRepository {
fn remote(&self, id: &RemoteId) -> Result<Remote, refs::Error> { fn remote(&self, id: &RemoteId) -> Result<Remote, refs::Error> {
self.remotes self.remotes
.get(id) .get(id)
.map(|refs| Remote { .map(|refs| Remote { refs: refs.clone() })
refs: refs.sigrefs.clone(),
})
.ok_or(refs::Error::InvalidRef) .ok_or(refs::Error::InvalidRef)
} }
@ -191,14 +189,7 @@ impl RemoteRepository for MockRepository {
Ok(self Ok(self
.remotes .remotes
.iter() .iter()
.map(|(id, refs)| { .map(|(id, refs)| (*id, Remote { refs: refs.clone() }))
(
*id,
Remote {
refs: refs.sigrefs.clone(),
},
)
})
.collect()) .collect())
} }
@ -379,14 +370,14 @@ impl SignRepository for MockRepository {
fn sign_refs<G: crypto::signature::Signer<crypto::Signature>>( fn sign_refs<G: crypto::signature::Signer<crypto::Signature>>(
&self, &self,
_signer: &Device<G>, _signer: &Device<G>,
) -> Result<crate::storage::refs::SignedRefs, RepositoryError> { ) -> Result<crate::storage::refs::SignedRefsAt, RepositoryError> {
todo!() todo!()
} }
fn force_sign_refs<G: crypto::signature::Signer<crypto::Signature>>( fn force_sign_refs<G: crypto::signature::Signer<crypto::Signature>>(
&self, &self,
_signer: &Device<G>, _signer: &Device<G>,
) -> Result<crate::storage::refs::SignedRefs, RepositoryError> { ) -> Result<crate::storage::refs::SignedRefsAt, RepositoryError> {
todo!() todo!()
} }
} }