Skip to main content

ic_backup/ops/persistence/download_journal/local_restore_source/
mod.rs

1//! Explicit fresh original local source verification under both layout guards.
2
3use super::{DownloadIntegrityError, DownloadJournalGuard, DownloadManifestError};
4use crate::{
5    model::{operation_plan::OperationPlanRecord, restore_safety::RestoreSafetyRequirementRecord},
6    ops::persistence::{
7        BackupLayoutGuard, RestoreSafetyPersistenceError, read_restore_safety_requirement,
8    },
9    policy::local_restore_source::{
10        LocalRestoreSourcePolicyError, LocalRestoreSourceView, validate,
11    },
12};
13use thiserror::Error;
14
15impl DownloadJournalGuard<'_> {
16    /// Freshly verify the complete original local source and project exact restore artifacts.
17    ///
18    /// The source journal borrows its source layout; the returned view also borrows
19    /// the restore layout, both plans and original safety requirement. Exact retained
20    /// requirement/plans, manifest and journal are admitted before and after fresh
21    /// no-follow verification of every original source artifact, including any outside
22    /// a restore subset. Replay/ordinary resume never invoke this separate operation.
23    /// No records, allowances, references or fences change; no provider is invoked.
24    /// Integrations own stable noncooperating bytes, authenticated snapshot/transfer
25    /// completeness and application subset safety. Success grants no upload/load,
26    /// current permissions, signing, fence/reference release or terminal authority.
27    /// # Errors
28    /// Rejects absent/unsafe/changed originals, another source digest, non-durable or
29    /// incomplete selected sets, changed bytes, replaced custody and contention.
30    pub fn verify_local_restore_source<'a>(
31        &'a self,
32        restore_layout: &'a BackupLayoutGuard,
33        restore: &'a OperationPlanRecord,
34        source: &'a OperationPlanRecord,
35        requirement: &'a RestoreSafetyRequirementRecord,
36    ) -> Result<LocalRestoreSourceView<'a>, LocalRestoreSourceError> {
37        self.admit_local_restore_source(restore_layout, restore, source, requirement)?;
38        self.verify_durable_artifacts(source)?;
39        self.admit_local_restore_source(restore_layout, restore, source, requirement)
40    }
41
42    pub(super) fn admit_local_restore_source<'a>(
43        &'a self,
44        restore_layout: &'a BackupLayoutGuard,
45        restore: &'a OperationPlanRecord,
46        source: &'a OperationPlanRecord,
47        requirement: &'a RestoreSafetyRequirementRecord,
48    ) -> Result<LocalRestoreSourceView<'a>, LocalRestoreSourceError> {
49        read_restore_safety_requirement(
50            restore_layout,
51            self.layout,
52            restore,
53            source,
54            &requirement.digest(),
55        )?;
56        self.read_download_manifest(source, requirement.source_artifacts())?;
57        restore_layout
58            .check_root()
59            .map_err(DownloadIntegrityError::from)?;
60        Ok(validate(
61            restore,
62            source,
63            requirement,
64            self.record().map_err(DownloadIntegrityError::from)?,
65        )?)
66    }
67}
68
69/// Typed fresh original local source denial, preserving every original obligation.
70#[derive(Debug, Error)]
71pub enum LocalRestoreSourceError {
72    /// Original requirement and both retained plans cannot be admitted.
73    #[error(transparent)]
74    Requirement(#[from] RestoreSafetyPersistenceError),
75    /// Exact original immutable manifest or guarded journal differs.
76    #[error(transparent)]
77    Manifest(#[from] DownloadManifestError),
78    /// Pure same-ID local source admission failed.
79    #[error(transparent)]
80    Policy(#[from] LocalRestoreSourcePolicyError),
81    /// Fresh guarded local byte/custody verification failed.
82    #[error(transparent)]
83    Integrity(#[from] DownloadIntegrityError),
84}
85
86#[cfg(all(test, unix))]
87mod tests;