use std::path::Path;
use crate::adapters::secondary::SpecDigestReader;
use crate::domain::manifest::{Manifest, ManifestError};
pub fn verify_vendored_specs(spec_root: &Path) -> Result<Manifest, VerifyError> {
let reader = SpecDigestReader::new(spec_root);
let source = reader.read_manifest().map_err(VerifyError::Io)?;
let manifest = Manifest::parse(&source)?;
manifest
.verify(
|revision, file| reader.digest(revision, file),
|revision| reader.files_in(revision).unwrap_or_default(),
)
.map_err(VerifyError::Manifest)?;
Ok(manifest)
}
#[derive(Debug, thiserror::Error)]
pub enum VerifyError {
#[error("could not read the vendored spec tree: {0}")]
Io(String),
#[error(transparent)]
Manifest(#[from] ManifestError),
}
#[cfg(test)]
mod tests {
#![expect(
clippy::expect_used,
reason = "tests assert on fallible calls; propagating errors would replace a clear failure message with noise"
)]
use super::{VerifyError, verify_vendored_specs};
use std::path::{Path, PathBuf};
fn shipped_spec_root() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR")).join("spec")
}
#[test]
fn the_shipped_tree_verifies() {
let manifest = verify_vendored_specs(&shipped_spec_root())
.expect("the vendored spec tree must match its manifest");
assert!(
manifest.revision_names().len() >= 6,
"expected all revisions to be vendored"
);
}
#[test]
fn a_spec_root_without_a_manifest_is_an_io_error() {
let scratch = std::env::temp_dir().join("protocol-droid-verify-no-manifest");
let _ = std::fs::remove_dir_all(&scratch);
std::fs::create_dir_all(&scratch).expect("create scratch");
let error = verify_vendored_specs(&scratch).expect_err("must fail");
assert!(
matches!(error, VerifyError::Io(_)),
"expected an Io error, got {error:?}"
);
let _ = std::fs::remove_dir_all(&scratch);
}
#[test]
fn a_malformed_manifest_is_a_manifest_error() {
let scratch = std::env::temp_dir().join("protocol-droid-verify-bad-manifest");
let _ = std::fs::remove_dir_all(&scratch);
std::fs::create_dir_all(&scratch).expect("create scratch");
std::fs::write(scratch.join("MANIFEST.toml"), "not toml at all").expect("write manifest");
let error = verify_vendored_specs(&scratch).expect_err("must fail");
assert!(
matches!(error, VerifyError::Manifest(_)),
"expected a Manifest error, got {error:?}"
);
let _ = std::fs::remove_dir_all(&scratch);
}
}