use super::super::json::read_record;
use super::{DownloadJournalError, DownloadJournalGuard};
use crate::{
model::{
artifacts::ChecksumError,
download_journal::{DownloadJournalRecord, MAX_DOWNLOAD_JOURNAL_BYTES},
operation_plan::OperationPlanRecord,
},
ops::{
artifacts::{ArtifactError, checksum_directory},
persistence::{OperationPlanPersistenceError, PersistenceError, read_operation_plan},
},
policy::download_integrity::{DownloadIntegrityPolicyError, validate},
};
use thiserror::Error;
impl DownloadJournalGuard<'_> {
pub(super) fn verify_manifest_source(
&self,
plan: &OperationPlanRecord,
) -> Result<(), DownloadIntegrityError> {
self.admit_integrity_original(plan)?;
let expected = validate(plan, &self.record)?;
self.check_artifact_parent()?;
let path = self
.layout
.root()
.join(self.record.artifacts()[0].artifact_path());
checksum_directory(&path)?.verify(expected.hash())?;
self.admit_integrity_original(plan)?;
Ok(())
}
pub(super) fn admit_integrity_original(
&self,
plan: &OperationPlanRecord,
) -> Result<(), DownloadIntegrityError> {
self.check_usable()?;
read_operation_plan(self.layout, &plan.digest())?;
self.require_unchanged_integrity_journal()
}
pub(super) fn require_unchanged_integrity_journal(&self) -> Result<(), DownloadIntegrityError> {
let retained: DownloadJournalRecord =
read_record(&self.path(), MAX_DOWNLOAD_JOURNAL_BYTES)?;
if retained != self.record {
return Err(DownloadIntegrityError::JournalChanged);
}
Ok(())
}
}
#[derive(Debug, Error)]
pub enum DownloadIntegrityError {
#[error("retained download journal changed during integrity verification")]
JournalChanged,
#[error(transparent)]
Journal(#[from] DownloadJournalError),
#[error(transparent)]
Plan(#[from] OperationPlanPersistenceError),
#[error(transparent)]
Policy(#[from] DownloadIntegrityPolicyError),
#[error(transparent)]
Persistence(#[from] PersistenceError),
#[error(transparent)]
Artifact(#[from] ArtifactError),
#[error(transparent)]
Checksum(#[from] ChecksumError),
}
#[cfg(all(test, unix))]
mod tests;