cordance-cortex 0.1.1

Cordance Cortex adapter. Emits candidate receipts; never writes to the cortex repo or runtime.
Documentation
//! Structural validator for `CortexReceiptV1Candidate`.
//!
//! Checks invariants that must hold before the receipt is emitted:
//! - Correct schema tag.
//! - `authority_boundary.candidate_only` is `true`.
//! - All eight authority-grant flags are `false`.
//! - `forbidden_uses` and `allowed_claim_language` are non-empty.

use cordance_core::receipt::CortexReceiptV1Candidate;
use cordance_core::schema;

use crate::CortexError;

/// Validate a receipt's structural invariants.
///
/// # Errors
/// Returns `CortexError::Validation` with a description of the first failed
/// check.
pub fn validate_receipt(receipt: &CortexReceiptV1Candidate) -> Result<(), CortexError> {
    // 1. Schema tag.
    if receipt.schema != schema::CORDANCE_CORTEX_RECEIPT_V1_CANDIDATE {
        return Err(CortexError::Validation(format!(
            "wrong schema: expected '{}', got '{}'",
            schema::CORDANCE_CORTEX_RECEIPT_V1_CANDIDATE,
            receipt.schema,
        )));
    }

    let ab = &receipt.authority_boundary;

    // 2. candidate_only must be true.
    if !ab.candidate_only {
        return Err(CortexError::Validation(
            "authority_boundary.candidate_only must be true".into(),
        ));
    }

    // 3. All eight authority-grant flags must be false.
    if ab.cortex_truth_allowed {
        return Err(CortexError::Validation(
            "authority_boundary.cortex_truth_allowed must be false".into(),
        ));
    }
    if ab.cortex_admission_allowed {
        return Err(CortexError::Validation(
            "authority_boundary.cortex_admission_allowed must be false".into(),
        ));
    }
    if ab.durable_promotion_allowed {
        return Err(CortexError::Validation(
            "authority_boundary.durable_promotion_allowed must be false".into(),
        ));
    }
    if ab.memory_promotion_allowed {
        return Err(CortexError::Validation(
            "authority_boundary.memory_promotion_allowed must be false".into(),
        ));
    }
    if ab.doctrine_promotion_allowed {
        return Err(CortexError::Validation(
            "authority_boundary.doctrine_promotion_allowed must be false".into(),
        ));
    }
    if ab.trusted_history_allowed {
        return Err(CortexError::Validation(
            "authority_boundary.trusted_history_allowed must be false".into(),
        ));
    }
    if ab.release_acceptance_allowed {
        return Err(CortexError::Validation(
            "authority_boundary.release_acceptance_allowed must be false".into(),
        ));
    }
    if ab.runtime_authority_allowed {
        return Err(CortexError::Validation(
            "authority_boundary.runtime_authority_allowed must be false".into(),
        ));
    }

    let body = &receipt.cordance_execution_receipt_v1;

    // 4. forbidden_uses non-empty.
    if body.forbidden_uses.is_empty() {
        return Err(CortexError::Validation(
            "forbidden_uses must not be empty".into(),
        ));
    }

    // 5. allowed_claim_language non-empty.
    if body.allowed_claim_language.is_empty() {
        return Err(CortexError::Validation(
            "allowed_claim_language must not be empty".into(),
        ));
    }

    Ok(())
}