ic-backup 0.24.2

Host-side snapshot backup and same-release recovery for Internet Computer canisters
Documentation
//! Bounded immutable original-plan consistency requirement retention; no fence authority.

use super::{
    BackupLayoutGuard, JournalLockError, OperationPlanPersistenceError, PersistenceError,
    immutable_record, read_operation_plan,
};
use crate::model::{
    artifacts::ArtifactChecksumRecord,
    consistency::{
        ConsistencyRequirementError, ConsistencyRequirementRecord,
        MAX_CONSISTENCY_REQUIREMENT_BYTES,
    },
    operation_plan::OperationPlanRecord,
};
use thiserror::Error;

/// Durably create fixed `consistency-requirement.json` without replacing original evidence.
///
/// Requires the exact original plan already retained under layout exclusion. This
/// persists the reviewed guarantee, not an active fence, paid allowance or release permit.
/// # Errors
/// Rejects mismatched/missing original plan, excessive bytes, unsafe/existing paths and IO/locks.
pub fn create_consistency_requirement(
    layout: &BackupLayoutGuard,
    plan: &OperationPlanRecord,
    record: &ConsistencyRequirementRecord,
) -> Result<(), ConsistencyPersistenceError> {
    record.validate_plan(plan)?;
    read_operation_plan(layout, &plan.digest())?;
    immutable_record::create(
        layout,
        "consistency-requirement.json",
        MAX_CONSISTENCY_REQUIREMENT_BYTES,
        record,
    )
}
/// Read bounded validated original requirement under its exact expected digest and retained plan.
///
/// Lost local creation replies reconcile by this read; never overwrite/downgrade an
/// existing guarantee or recover a fence/consumed authority from absence.
/// # Errors
/// Rejects unsafe/missing/oversized/invalid declarations, original plan or requirement mismatch.
pub fn read_consistency_requirement(
    layout: &BackupLayoutGuard,
    plan: &OperationPlanRecord,
    expected: &ArtifactChecksumRecord,
) -> Result<ConsistencyRequirementRecord, ConsistencyPersistenceError> {
    read_operation_plan(layout, &plan.digest())?;
    immutable_record::read_with(
        layout,
        "consistency-requirement.json",
        MAX_CONSISTENCY_REQUIREMENT_BYTES,
        |record: &ConsistencyRequirementRecord| {
            record.validate_plan(plan)?;
            if &record.digest() != expected {
                return Err(ConsistencyPersistenceError::DigestMismatch);
            }
            Ok(())
        },
    )
}
/// Typed exact retained requirement or bounded local storage denial.
#[derive(Debug, Error)]
pub enum ConsistencyPersistenceError {
    /// Retained guarantee differs from the exact originally expected requirement.
    #[error("consistency requirement digest mismatch")]
    DigestMismatch,
    /// Original full plan identity differs.
    #[error(transparent)]
    Requirement(#[from] ConsistencyRequirementError),
    /// Original plan is not admitted from the held layout.
    #[error(transparent)]
    Plan(#[from] OperationPlanPersistenceError),
    /// Layout/journal exclusion failed.
    #[error(transparent)]
    Lock(#[from] JournalLockError),
    /// Bounded JSON or durable filesystem access failed.
    #[error(transparent)]
    Persistence(#[from] PersistenceError),
}

#[cfg(all(test, unix))]
mod tests;