node: Improve verification function

This commit is contained in:
Alexis Sellier 2022-09-14 18:20:57 +02:00
parent 38dc571f2e
commit 59ccfdda77
No known key found for this signature in database
2 changed files with 34 additions and 9 deletions

View File

@ -163,6 +163,8 @@ pub enum VerifyError {
Refs(#[from] refs::Error), Refs(#[from] refs::Error),
#[error("unknown reference `{1}` in remote `{0}`")] #[error("unknown reference `{1}` in remote `{0}`")]
UnknownRef(RemoteId, git::RefString), UnknownRef(RemoteId, git::RefString),
#[error("missing reference `{1}` in remote `{0}`")]
MissingRef(RemoteId, git::RefString),
#[error("git: {0}")] #[error("git: {0}")]
Git(#[from] git2::Error), Git(#[from] git2::Error),
} }
@ -200,29 +202,43 @@ impl Repository {
} }
pub fn verify(&self) -> Result<(), VerifyError> { pub fn verify(&self) -> Result<(), VerifyError> {
let remotes = self.remotes()?.collect::<Result<HashMap<_, _>, _>>()?; let mut remotes: HashMap<RemoteId, Refs> = self
.remotes()?
.map(|remote| {
let (id, remote) = remote?;
Ok((id, remote.refs.into()))
})
.collect::<Result<_, VerifyError>>()?;
for r in self.backend.references()? { for r in self.backend.references()? {
let r = r?; let r = r?;
let name = r.name().ok_or(VerifyError::InvalidRef)?; let name = r.name().ok_or(VerifyError::InvalidRef)?;
let oid = r.target().ok_or(VerifyError::InvalidRef)?; let oid = r.target().ok_or(VerifyError::InvalidRef)?;
let (remote, refname) = git::parse_ref::<RemoteId>(name)?; let (remote_id, refname) = git::parse_ref::<RemoteId>(name)?;
if refname == *refs::SIGNATURE_REF { if refname == *refs::SIGNATURE_REF {
continue; continue;
} }
let remote = remotes let remote = remotes
.get(&remote) .get_mut(&remote_id)
.ok_or(VerifyError::InvalidRemote(remote))?; .ok_or(VerifyError::InvalidRemote(remote_id))?;
let signed_oid = remote let signed_oid = remote
.refs .remove(&refname)
.get(&refname) .ok_or_else(|| VerifyError::UnknownRef(remote_id, refname.clone()))?;
.ok_or_else(|| VerifyError::UnknownRef(remote.id, refname.clone()))?;
if git::Oid::from(oid) != *signed_oid { if git::Oid::from(oid) != signed_oid {
return Err(VerifyError::InvalidRefTarget(remote.id, refname, oid)); return Err(VerifyError::InvalidRefTarget(remote_id, refname, oid));
} }
} }
// The refs that are left in the map, are ones that were signed, but are not
// in the repository.
for (id, refs) in remotes.into_iter() {
if let Some((name, _)) = refs.into_iter().next() {
return Err(VerifyError::MissingRef(id, name));
}
}
Ok(()) Ok(())
} }

View File

@ -123,6 +123,15 @@ impl Refs {
} }
} }
impl IntoIterator for Refs {
type Item = (git::RefString, Oid);
type IntoIter = std::collections::btree_map::IntoIter<git::RefString, Oid>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl From<Refs> for BTreeMap<git::RefString, Oid> { impl From<Refs> for BTreeMap<git::RefString, Oid> {
fn from(refs: Refs) -> Self { fn from(refs: Refs) -> Self {
refs.0 refs.0