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,
SignedRefsAt { sigrefs, .. }: SignedRefsAt,
) -> 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)?;
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::identity::{Did, Doc, DocError};
use radicle::prelude::Verified;
use radicle::storage;
use radicle::storage::git::Repository;
use radicle::storage::refs::RefsAt;
@ -709,7 +708,7 @@ where
self.handle.repository().remote(remote)
}
fn remotes(&self) -> Result<Remotes<Verified>, storage::refs::Error> {
fn remotes(&self) -> Result<Remotes, storage::refs::Error> {
self.state
.sigrefs
.keys()

View File

@ -7,7 +7,6 @@ use std::sync::LazyLock;
use thiserror::Error;
use crate::cob::ObjectId;
use crate::crypto::Verified;
use crate::git;
use crate::git::BranchName;
use crate::identity::doc;
@ -56,7 +55,7 @@ pub fn init<G, S>(
visibility: Visibility,
signer: &Device<G>,
storage: S,
) -> Result<(RepoId, identity::Doc, SignedRefs<Verified>), InitError>
) -> Result<(RepoId, identity::Doc, SignedRefs), InitError>
where
G: crypto::signature::Signer<crypto::Signature>,
S: WriteStorage,
@ -103,7 +102,7 @@ fn init_configure<G>(
url: &git::Url,
identity: git::Oid,
signer: &Device<G>,
) -> Result<SignedRefs<Verified>, InitError>
) -> Result<SignedRefs, InitError>
where
G: crypto::signature::Signer<crypto::Signature>,
{

View File

@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize};
use thiserror::Error;
pub use crate::git::Oid;
use crypto::{PublicKey, Unverified, Verified};
use crypto::PublicKey;
pub use git::{Validation, Validations};
use crate::cob;
@ -313,46 +313,40 @@ impl fmt::Display for RefUpdate {
}
/// Project remotes. Tracks the git state of a project.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Remotes<V>(RandomMap<RemoteId, Remote<V>>);
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct Remotes(RandomMap<RemoteId, Remote>);
impl<V> FromIterator<(RemoteId, Remote<V>)> for Remotes<V> {
fn from_iter<T: IntoIterator<Item = (RemoteId, Remote<V>)>>(iter: T) -> Self {
impl FromIterator<(RemoteId, Remote)> for Remotes {
fn from_iter<T: IntoIterator<Item = (RemoteId, Remote)>>(iter: T) -> Self {
Self(iter.into_iter().collect())
}
}
impl<V> Deref for Remotes<V> {
type Target = RandomMap<RemoteId, Remote<V>>;
impl Deref for Remotes {
type Target = RandomMap<RemoteId, Remote>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<V> Remotes<V> {
pub fn new(remotes: RandomMap<RemoteId, Remote<V>>) -> Self {
impl Remotes {
pub fn new(remotes: RandomMap<RemoteId, Remote>) -> Self {
Self(remotes)
}
}
impl<V> Default for Remotes<V> {
fn default() -> Self {
Self(RandomMap::default())
}
}
impl<V> IntoIterator for Remotes<V> {
type Item = (RemoteId, Remote<V>);
type IntoIter = hash_map::IntoIter<RemoteId, Remote<V>>;
impl IntoIterator for Remotes {
type Item = (RemoteId, Remote);
type IntoIter = hash_map::IntoIter<RemoteId, Remote>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<V> From<Remotes<V>> for RandomMap<RemoteId, Refs> {
fn from(other: Remotes<V>) -> Self {
impl From<Remotes> for RandomMap<RemoteId, Refs> {
fn from(other: Remotes) -> Self {
let mut remotes = RandomMap::with_hasher(fastrand::Rng::new().into());
for (k, v) in other.into_iter() {
@ -364,22 +358,15 @@ impl<V> From<Remotes<V>> for RandomMap<RemoteId, Refs> {
/// A project remote.
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct Remote<V = Verified> {
pub struct Remote {
/// Git references published under this remote, and their hashes.
#[serde(flatten)]
pub refs: SignedRefs<V>,
pub refs: SignedRefs,
}
impl Remote<Unverified> {
/// Create a new unverified remotes object.
pub fn new(refs: impl Into<SignedRefs<Unverified>>) -> Self {
Self { refs: refs.into() }
}
}
impl Remote<Verified> {
/// Create a new unverified remotes object.
pub fn new(refs: impl Into<SignedRefs<Verified>>) -> Self {
impl Remote {
/// Create a new remotes object.
pub fn new(refs: impl Into<SignedRefs>) -> Self {
Self { refs: refs.into() }
}
@ -400,8 +387,8 @@ impl Remote<Verified> {
}
}
impl<V> Deref for Remote<V> {
type Target = SignedRefs<V>;
impl Deref for Remote {
type Target = SignedRefs;
fn deref(&self) -> &Self::Target {
&self.refs
@ -605,10 +592,10 @@ pub trait ReadRepository: Sized + ValidateRepository {
/// Access the remotes of a repository.
pub trait RemoteRepository {
/// 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.
fn remotes(&self) -> Result<Remotes<Verified>, refs::Error>;
fn remotes(&self) -> Result<Remotes, refs::Error>;
/// Get [`RefsAt`] of all remotes.
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.
/// 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.
@ -670,7 +657,7 @@ pub trait WriteRepository: ReadRepository + SignRepository {
/// Allows signing refs.
pub trait SignRepository {
/// 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
G: crypto::signature::Signer<crypto::Signature>;
}

View File

@ -11,8 +11,6 @@ use std::path::{Path, PathBuf};
use std::sync::LazyLock;
use std::{fs, io};
use crypto::Verified;
use crate::git::canonical::Quorum;
use crate::git::raw::ErrorExt as _;
use crate::identity::crefs::GetCanonicalRefs as _;
@ -590,10 +588,8 @@ impl Repository {
pub fn remotes(
&self,
) -> Result<
impl Iterator<Item = Result<(RemoteId, Remote<Verified>), refs::Error>> + '_,
git::raw::Error,
> {
) -> Result<impl Iterator<Item = Result<(RemoteId, Remote), refs::Error>> + '_, git::raw::Error>
{
let remotes =
self.backend
.references_glob(SIGREFS_GLOB.as_str())?
@ -610,7 +606,7 @@ impl 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();
for remote in Repository::remotes(self)? {
remotes.push(remote?);
@ -618,9 +614,9 @@ impl RemoteRepository for Repository {
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)?;
Ok(Remote::<Verified>::new(refs))
Ok(Remote::new(refs))
}
fn remote_refs_at(&self) -> Result<Vec<RefsAt>, refs::Error> {
@ -637,7 +633,7 @@ impl RemoteRepository 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.
let mut signed = BTreeMap::from((*remote.refs).clone());
let mut failures = Validations::default();
@ -990,7 +986,7 @@ impl SignRepository for Repository {
fn sign_refs<G: crypto::signature::Signer<crypto::Signature>>(
&self,
signer: &Device<G>,
) -> Result<SignedRefs<Verified>, RepositoryError> {
) -> Result<SignedRefs, RepositoryError> {
let remote = signer.public_key();
// Ensure the root reference is set, which is checked during sigref verification.
if self

View File

@ -22,7 +22,7 @@ use crate::storage;
use crate::storage::Error;
use crate::storage::{
git::{Remote, Remotes, Validations},
ReadRepository, Verified,
ReadRepository,
};
use super::{RemoteId, Repository};
@ -239,7 +239,7 @@ where
fn sign_refs<G: crypto::signature::Signer<crypto::Signature>>(
&self,
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.
// Instead, we just return the existing signed refs.
let remote = self.repo.remote(signer.public_key())?;
@ -249,11 +249,11 @@ where
}
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)
}
fn remotes(&self) -> Result<Remotes<Verified>, storage::refs::Error> {
fn remotes(&self) -> Result<Remotes, storage::refs::Error> {
RemoteRepository::remotes(self.repo)
}
@ -263,7 +263,7 @@ impl<R: storage::RemoteRepository> RemoteRepository 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)
}
}

View File

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

View File

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

View File

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

View File

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

View File

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