radicle: Remove generics for verification markers

`SignedRefs` are now always verified.
This commit is contained in:
Lorenz Leutgeb 2026-03-16 13:34:42 +01:00
parent 393eca3976
commit 304a66311a
No known key found for this signature in database
11 changed files with 55 additions and 95 deletions

View File

@ -93,7 +93,7 @@ pub(crate) fn validate(
repo: &impl ValidateRepository, repo: &impl ValidateRepository,
SignedRefsAt { sigrefs, .. }: SignedRefsAt, SignedRefsAt { sigrefs, .. }: SignedRefsAt,
) -> Result<Option<Validations>, radicle::storage::Error> { ) -> Result<Option<Validations>, radicle::storage::Error> {
let remote = radicle::storage::Remote::<radicle::crypto::Verified>::new(sigrefs); let remote = radicle::storage::Remote::new(sigrefs);
let validations = repo.validate_remote(&remote)?; let validations = repo.validate_remote(&remote)?;
Ok(validations.is_empty().not().then_some(validations)) Ok(validations.is_empty().not().then_some(validations))
} }

View File

@ -6,7 +6,6 @@ use radicle::crypto::PublicKey;
use radicle::git::{fmt::Qualified, Oid}; use radicle::git::{fmt::Qualified, Oid};
use radicle::identity::{Did, Doc, DocError}; use radicle::identity::{Did, Doc, DocError};
use radicle::prelude::Verified;
use radicle::storage; use radicle::storage;
use radicle::storage::git::Repository; use radicle::storage::git::Repository;
use radicle::storage::refs::RefsAt; use radicle::storage::refs::RefsAt;
@ -709,7 +708,7 @@ where
self.handle.repository().remote(remote) self.handle.repository().remote(remote)
} }
fn remotes(&self) -> Result<Remotes<Verified>, storage::refs::Error> { fn remotes(&self) -> Result<Remotes, storage::refs::Error> {
self.state self.state
.sigrefs .sigrefs
.keys() .keys()

View File

@ -7,7 +7,6 @@ use std::sync::LazyLock;
use thiserror::Error; use thiserror::Error;
use crate::cob::ObjectId; use crate::cob::ObjectId;
use crate::crypto::Verified;
use crate::git; use crate::git;
use crate::git::BranchName; use crate::git::BranchName;
use crate::identity::doc; use crate::identity::doc;
@ -56,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<Verified>), InitError> ) -> Result<(RepoId, identity::Doc, SignedRefs), InitError>
where where
G: crypto::signature::Signer<crypto::Signature>, G: crypto::signature::Signer<crypto::Signature>,
S: WriteStorage, S: WriteStorage,
@ -103,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<Verified>, InitError> ) -> Result<SignedRefs, InitError>
where where
G: crypto::signature::Signer<crypto::Signature>, G: crypto::signature::Signer<crypto::Signature>,
{ {

View File

@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize};
use thiserror::Error; use thiserror::Error;
pub use crate::git::Oid; pub use crate::git::Oid;
use crypto::{PublicKey, Unverified, Verified}; use crypto::PublicKey;
pub use git::{Validation, Validations}; pub use git::{Validation, Validations};
use crate::cob; use crate::cob;
@ -313,46 +313,40 @@ impl fmt::Display for RefUpdate {
} }
/// Project remotes. Tracks the git state of a project. /// Project remotes. Tracks the git state of a project.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct Remotes<V>(RandomMap<RemoteId, Remote<V>>); pub struct Remotes(RandomMap<RemoteId, Remote>);
impl<V> FromIterator<(RemoteId, Remote<V>)> for Remotes<V> { impl FromIterator<(RemoteId, Remote)> for Remotes {
fn from_iter<T: IntoIterator<Item = (RemoteId, Remote<V>)>>(iter: T) -> Self { fn from_iter<T: IntoIterator<Item = (RemoteId, Remote)>>(iter: T) -> Self {
Self(iter.into_iter().collect()) Self(iter.into_iter().collect())
} }
} }
impl<V> Deref for Remotes<V> { impl Deref for Remotes {
type Target = RandomMap<RemoteId, Remote<V>>; type Target = RandomMap<RemoteId, Remote>;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.0 &self.0
} }
} }
impl<V> Remotes<V> { impl Remotes {
pub fn new(remotes: RandomMap<RemoteId, Remote<V>>) -> Self { pub fn new(remotes: RandomMap<RemoteId, Remote>) -> Self {
Self(remotes) Self(remotes)
} }
} }
impl<V> Default for Remotes<V> { impl IntoIterator for Remotes {
fn default() -> Self { type Item = (RemoteId, Remote);
Self(RandomMap::default()) type IntoIter = hash_map::IntoIter<RemoteId, Remote>;
}
}
impl<V> IntoIterator for Remotes<V> {
type Item = (RemoteId, Remote<V>);
type IntoIter = hash_map::IntoIter<RemoteId, Remote<V>>;
fn into_iter(self) -> Self::IntoIter { fn into_iter(self) -> Self::IntoIter {
self.0.into_iter() self.0.into_iter()
} }
} }
impl<V> From<Remotes<V>> for RandomMap<RemoteId, Refs> { impl From<Remotes> for RandomMap<RemoteId, Refs> {
fn from(other: Remotes<V>) -> 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() {
@ -364,22 +358,15 @@ impl<V> From<Remotes<V>> for RandomMap<RemoteId, Refs> {
/// A project remote. /// A project remote.
#[derive(Debug, Clone, PartialEq, Eq, Serialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct Remote<V = Verified> { 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<V>, pub refs: SignedRefs,
} }
impl Remote<Unverified> { impl Remote {
/// Create a new unverified remotes object. /// Create a new remotes object.
pub fn new(refs: impl Into<SignedRefs<Unverified>>) -> Self { pub fn new(refs: impl Into<SignedRefs>) -> Self {
Self { refs: refs.into() }
}
}
impl Remote<Verified> {
/// Create a new unverified remotes object.
pub fn new(refs: impl Into<SignedRefs<Verified>>) -> Self {
Self { refs: refs.into() } Self { refs: refs.into() }
} }
@ -400,8 +387,8 @@ impl Remote<Verified> {
} }
} }
impl<V> Deref for Remote<V> { impl Deref for Remote {
type Target = SignedRefs<V>; type Target = SignedRefs;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.refs &self.refs
@ -605,10 +592,10 @@ pub trait ReadRepository: Sized + ValidateRepository {
/// Access the remotes of a repository. /// Access the remotes of a repository.
pub trait RemoteRepository { pub trait RemoteRepository {
/// Get the given remote. /// Get the given remote.
fn remote(&self, remote: &RemoteId) -> Result<Remote<Verified>, refs::Error>; fn remote(&self, remote: &RemoteId) -> Result<Remote, refs::Error>;
/// Get all remotes. /// Get all remotes.
fn remotes(&self) -> Result<Remotes<Verified>, refs::Error>; fn remotes(&self) -> Result<Remotes, refs::Error>;
/// Get [`RefsAt`] of all remotes. /// Get [`RefsAt`] of all remotes.
fn remote_refs_at(&self) -> Result<Vec<RefsAt>, refs::Error>; fn remote_refs_at(&self) -> Result<Vec<RefsAt>, refs::Error>;
@ -631,7 +618,7 @@ where
/// ///
/// Returns any ref found under that remote that isn't signed. /// Returns any ref found under that remote that isn't signed.
/// If a signed ref is missing from the repository, an error is returned. /// If a signed ref is missing from the repository, an error is returned.
fn validate_remote(&self, remote: &Remote<Verified>) -> Result<Validations, Error>; fn validate_remote(&self, remote: &Remote) -> Result<Validations, Error>;
} }
/// Allows read-write access to a repository. /// Allows read-write access to a repository.
@ -670,7 +657,7 @@ 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<Verified>, RepositoryError> fn sign_refs<G>(&self, signer: &Device<G>) -> Result<SignedRefs, RepositoryError>
where where
G: crypto::signature::Signer<crypto::Signature>; G: crypto::signature::Signer<crypto::Signature>;
} }

View File

@ -11,8 +11,6 @@ use std::path::{Path, PathBuf};
use std::sync::LazyLock; use std::sync::LazyLock;
use std::{fs, io}; use std::{fs, io};
use crypto::Verified;
use crate::git::canonical::Quorum; use crate::git::canonical::Quorum;
use crate::git::raw::ErrorExt as _; use crate::git::raw::ErrorExt as _;
use crate::identity::crefs::GetCanonicalRefs as _; use crate::identity::crefs::GetCanonicalRefs as _;
@ -590,10 +588,8 @@ impl Repository {
pub fn remotes( pub fn remotes(
&self, &self,
) -> Result< ) -> Result<impl Iterator<Item = Result<(RemoteId, Remote), refs::Error>> + '_, git::raw::Error>
impl Iterator<Item = Result<(RemoteId, Remote<Verified>), refs::Error>> + '_, {
git::raw::Error,
> {
let remotes = let remotes =
self.backend self.backend
.references_glob(SIGREFS_GLOB.as_str())? .references_glob(SIGREFS_GLOB.as_str())?
@ -610,7 +606,7 @@ impl Repository {
} }
impl RemoteRepository for Repository { impl RemoteRepository for Repository {
fn remotes(&self) -> Result<Remotes<Verified>, refs::Error> { fn remotes(&self) -> Result<Remotes, refs::Error> {
let mut remotes = Vec::new(); let mut remotes = Vec::new();
for remote in Repository::remotes(self)? { for remote in Repository::remotes(self)? {
remotes.push(remote?); remotes.push(remote?);
@ -618,9 +614,9 @@ impl RemoteRepository for Repository {
Ok(Remotes::from_iter(remotes)) Ok(Remotes::from_iter(remotes))
} }
fn remote(&self, remote: &RemoteId) -> Result<Remote<Verified>, refs::Error> { fn remote(&self, remote: &RemoteId) -> Result<Remote, refs::Error> {
let refs = SignedRefs::load(*remote, self)?; let refs = SignedRefs::load(*remote, self)?;
Ok(Remote::<Verified>::new(refs)) Ok(Remote::new(refs))
} }
fn remote_refs_at(&self) -> Result<Vec<RefsAt>, refs::Error> { fn remote_refs_at(&self) -> Result<Vec<RefsAt>, refs::Error> {
@ -637,7 +633,7 @@ impl RemoteRepository for Repository {
} }
impl ValidateRepository for Repository { impl ValidateRepository for Repository {
fn validate_remote(&self, remote: &Remote<Verified>) -> 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).clone());
let mut failures = Validations::default(); let mut failures = Validations::default();
@ -990,7 +986,7 @@ 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<Verified>, RepositoryError> { ) -> Result<SignedRefs, 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

View File

@ -22,7 +22,7 @@ use crate::storage;
use crate::storage::Error; use crate::storage::Error;
use crate::storage::{ use crate::storage::{
git::{Remote, Remotes, Validations}, git::{Remote, Remotes, Validations},
ReadRepository, Verified, ReadRepository,
}; };
use super::{RemoteId, Repository}; use super::{RemoteId, Repository};
@ -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<Verified>, RepositoryError> { ) -> Result<storage::refs::SignedRefs, 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())?;
@ -249,11 +249,11 @@ where
} }
impl<R: storage::RemoteRepository> RemoteRepository for DraftStore<'_, R> { impl<R: storage::RemoteRepository> RemoteRepository for DraftStore<'_, R> {
fn remote(&self, id: &RemoteId) -> Result<Remote<Verified>, storage::refs::Error> { fn remote(&self, id: &RemoteId) -> Result<Remote, storage::refs::Error> {
self.repo.remote(id) self.repo.remote(id)
} }
fn remotes(&self) -> Result<Remotes<Verified>, storage::refs::Error> { fn remotes(&self) -> Result<Remotes, storage::refs::Error> {
RemoteRepository::remotes(self.repo) RemoteRepository::remotes(self.repo)
} }
@ -263,7 +263,7 @@ impl<R: storage::RemoteRepository> RemoteRepository for DraftStore<'_, R> {
} }
impl<R: storage::ValidateRepository> ValidateRepository for DraftStore<'_, R> { impl<R: storage::ValidateRepository> ValidateRepository for DraftStore<'_, R> {
fn validate_remote(&self, remote: &Remote<Verified>) -> Result<Validations, Error> { fn validate_remote(&self, remote: &Remote) -> Result<Validations, Error> {
self.repo.validate_remote(remote) self.repo.validate_remote(remote)
} }
} }

View File

@ -7,12 +7,11 @@ use std::collections::BTreeMap;
use std::fmt::Debug; use std::fmt::Debug;
use std::io; use std::io;
use std::io::{BufRead, BufReader}; use std::io::{BufRead, BufReader};
use std::marker::PhantomData;
use std::ops::Deref; use std::ops::Deref;
use std::str::FromStr; use std::str::FromStr;
use crypto::signature; use crypto::signature;
use crypto::{PublicKey, Signature, Verified}; use crypto::{PublicKey, Signature};
use radicle_core::NodeId; use radicle_core::NodeId;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use thiserror::Error; use thiserror::Error;
@ -99,7 +98,6 @@ impl Refs {
refs, refs,
signature, signature,
id: namespace, id: namespace,
_verified: PhantomData,
}; };
Ok(SignedRefsAt { Ok(SignedRefsAt {
sigrefs, sigrefs,
@ -227,8 +225,8 @@ impl From<Refs> for BTreeMap<git::fmt::RefString, Oid> {
} }
} }
impl<V> From<SignedRefs<V>> for Refs { impl From<SignedRefs> for Refs {
fn from(signed: SignedRefs<V>) -> Self { fn from(signed: SignedRefs) -> Self {
signed.refs signed.refs
} }
} }
@ -249,10 +247,8 @@ where
/// Combination of [`Refs`] and a [`Signature`]. The signature is a cryptographic /// Combination of [`Refs`] and a [`Signature`]. The signature is a cryptographic
/// signature over the refs. This allows us to easily verify if a set of refs /// signature over the refs. This allows us to easily verify if a set of refs
/// came from a particular key. /// came from a particular key.
///
/// The type parameter keeps track of whether the signature was [`Verified`].
#[derive(Debug, Clone, PartialEq, Eq, Serialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct SignedRefs<V> { pub struct SignedRefs {
/// The signed refs. /// The signed refs.
refs: Refs, refs: Refs,
/// The signature of the signer over the refs. /// The signature of the signer over the refs.
@ -260,12 +256,9 @@ pub struct SignedRefs<V> {
signature: Signature, signature: Signature,
/// This is the remote under which these refs exist, and the public key of the signer. /// This is the remote under which these refs exist, and the public key of the signer.
id: PublicKey, id: PublicKey,
#[serde(skip)]
_verified: PhantomData<V>,
} }
impl SignedRefs<Verified> { impl SignedRefs {
/// Returns the [`NodeId`] of the [`SignedRefs`]. /// Returns the [`NodeId`] of the [`SignedRefs`].
pub fn id(&self) -> NodeId { pub fn id(&self) -> NodeId {
self.id self.id
@ -290,7 +283,6 @@ impl SignedRefs<Verified> {
refs, refs,
signature, signature,
id: remote, id: remote,
_verified: PhantomData,
}) })
} }
@ -312,12 +304,11 @@ impl SignedRefs<Verified> {
refs, refs,
signature, signature,
id: remote, id: remote,
_verified: PhantomData,
}) })
} }
} }
impl<V> Deref for SignedRefs<V> { impl Deref for SignedRefs {
type Target = Refs; type Target = Refs;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
@ -379,7 +370,7 @@ impl std::fmt::Display for RefsAt {
/// [`Oid`]. /// [`Oid`].
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct SignedRefsAt { pub struct SignedRefsAt {
pub sigrefs: SignedRefs<Verified>, pub sigrefs: SignedRefs,
pub at: Oid, pub at: Oid,
} }
@ -423,7 +414,7 @@ impl SignedRefsAt {
} }
impl Deref for SignedRefsAt { impl Deref for SignedRefsAt {
type Target = SignedRefs<Verified>; type Target = SignedRefs;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.sigrefs &self.sigrefs

View File

@ -23,7 +23,6 @@ where
refs, refs,
signature, signature,
id: *signer.node_id(), id: *signer.node_id(),
_verified: PhantomData,
}; };
SignedRefsAt { SignedRefsAt {
sigrefs, sigrefs,

View File

@ -3,7 +3,6 @@ pub mod error;
#[cfg(test)] #[cfg(test)]
mod test; mod test;
use std::marker::PhantomData;
use std::path::Path; use std::path::Path;
use crypto::signature::Signer; use crypto::signature::Signer;
@ -176,7 +175,6 @@ impl Commit {
id, id,
signature: self.signature, signature: self.signature,
refs: self.refs, refs: self.refs,
_verified: PhantomData,
}, },
} }
} }

View File

@ -1,7 +1,7 @@
use std::path::Path; use std::path::Path;
use std::str::FromStr; use std::str::FromStr;
use crate::crypto::{PublicKey, Verified}; use crate::crypto::PublicKey;
use crate::git; use crate::git;
use crate::identity::doc::Visibility; use crate::identity::doc::Visibility;
use crate::identity::RepoId; use crate::identity::RepoId;
@ -72,15 +72,7 @@ pub fn project<P, G>(
path: P, path: P,
storage: &Storage, storage: &Storage,
signer: &Device<G>, signer: &Device<G>,
) -> Result< ) -> Result<(RepoId, SignedRefs, git::raw::Repository, git::raw::Oid), rad::InitError>
(
RepoId,
SignedRefs<Verified>,
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

@ -9,7 +9,6 @@ use crypto::PublicKey;
pub use crate::git; pub use crate::git;
use crate::git::fmt; use crate::git::fmt;
use crate::crypto::Verified;
use crate::identity::doc::{Doc, DocAt, DocError, RawDoc, RepoId}; use crate::identity::doc::{Doc, DocAt, DocError, RawDoc, RepoId};
use crate::node::device::Device; use crate::node::device::Device;
use crate::node::NodeId; use crate::node::NodeId;
@ -179,7 +178,7 @@ impl self::refs::sigrefs::git::reference::Reader for MockRepository {
} }
impl RemoteRepository for MockRepository { impl RemoteRepository for MockRepository {
fn remote(&self, id: &RemoteId) -> Result<Remote<Verified>, 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 {
@ -188,7 +187,7 @@ impl RemoteRepository for MockRepository {
.ok_or(refs::Error::InvalidRef) .ok_or(refs::Error::InvalidRef)
} }
fn remotes(&self) -> Result<Remotes<Verified>, refs::Error> { fn remotes(&self) -> Result<Remotes, refs::Error> {
Ok(self Ok(self
.remotes .remotes
.iter() .iter()
@ -216,7 +215,7 @@ impl RemoteRepository for MockRepository {
} }
impl ValidateRepository for MockRepository { impl ValidateRepository for MockRepository {
fn validate_remote(&self, _remote: &Remote<Verified>) -> Result<Validations, Error> { fn validate_remote(&self, _remote: &Remote) -> Result<Validations, Error> {
Ok(Validations::default()) Ok(Validations::default())
} }
} }
@ -380,7 +379,7 @@ 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<Verified>, RepositoryError> { ) -> Result<crate::storage::refs::SignedRefs, RepositoryError> {
todo!() todo!()
} }
} }