Skip to main content

ic_backup/policy/control_authority/
mod.rs

1//! Pure exact-result and direct caller-controller admission; no IO or dispatch authority.
2
3use crate::model::{
4    artifacts::ArtifactChecksumRecord,
5    control_authority::{ControlObservation, ControlObservationRequest, ControllerSet},
6};
7use thiserror::Error;
8
9/// Read-only matching controller evidence; not a dispatch permit or complete preflight.
10#[derive(Clone, Debug)]
11pub struct ControlAuthorityView<'a> {
12    request: ArtifactChecksumRecord,
13    observation: &'a ControlObservation,
14}
15impl ControlAuthorityView<'_> {
16    /// Read exact current original-intent/payload/challenge-bound request identity.
17    #[must_use]
18    pub const fn request(&self) -> &ArtifactChecksumRecord {
19        &self.request
20    }
21    /// Read matching canonical actual target.
22    #[must_use]
23    pub fn target(&self) -> &str {
24        self.observation.target()
25    }
26    /// Read complete known controller evidence.
27    #[must_use]
28    pub const fn controllers(&self) -> &ControllerSet {
29        self.observation.controllers()
30    }
31    /// Read opaque integration-owned evidence identifier.
32    #[must_use]
33    pub const fn evidence(&self) -> &ArtifactChecksumRecord {
34        self.observation.evidence()
35    }
36    /// Read reported calls without reserving, refunding or replenishing authority.
37    #[must_use]
38    pub const fn remote_observations(&self) -> u32 {
39        self.observation.remote_observations()
40    }
41}
42/// Match current request/context/target/call bound and exact caller-controller membership.
43///
44/// The caller qualifies actual provider authenticity, freshness and coherent custody.
45/// Policy performs no IO, record serialization, journal transition or scheduling.
46/// Other controllers, public/read visibility, Root paths and subnet-admin exceptions
47/// never substitute for the selected caller. Load still needs qualified snapshot-origin
48/// permissions and same-ID safety; controller membership is only one preflight component.
49/// # Errors
50/// Rejects changed request/context/target, excess calls and missing exact caller control.
51pub fn validate<'a>(
52    request: &ControlObservationRequest<'_>,
53    observation: &'a ControlObservation,
54) -> Result<ControlAuthorityView<'a>, ControlAuthorityError> {
55    let digest = request.digest();
56    if *observation.request() != digest {
57        return Err(ControlAuthorityError::RequestMismatch);
58    }
59    let binding = request.binding();
60    if let Some(field) = super::observed_context::first_mismatch(binding, observation.context()) {
61        return Err(ControlAuthorityError::ContextMismatch(field));
62    }
63    if observation.target() != binding.target() {
64        return Err(ControlAuthorityError::TargetMismatch);
65    }
66    if observation.remote_observations() > request.max_remote_observations() {
67        return Err(ControlAuthorityError::ObservationLimitExceeded {
68            limit: request.max_remote_observations(),
69            reported: observation.remote_observations(),
70        });
71    }
72    if !observation.controllers().contains_caller(binding) {
73        return Err(ControlAuthorityError::CallerNotController);
74    }
75    Ok(ControlAuthorityView {
76        request: digest,
77        observation,
78    })
79}
80/// Typed denial; no mismatch changes a plan/journal or admits any paid effect.
81#[derive(Debug, Eq, Error, PartialEq)]
82pub enum ControlAuthorityError {
83    /// Original intent/operation/payload/challenge/ceiling differs.
84    #[error("control observation request mismatch")]
85    RequestMismatch,
86    /// Actually observed context differs.
87    #[error("control observed {0} mismatch")]
88    ContextMismatch(&'static str),
89    /// Actually observed target differs.
90    #[error("control observed target mismatch")]
91    TargetMismatch,
92    /// Exact selected caller is absent; other access does not grant this lane.
93    #[error("selected caller is not an observed controller")]
94    CallerNotController,
95    /// Actual reported remote calls exceed the descriptive ceiling.
96    #[error("control reports {reported} observations above ceiling {limit}")]
97    ObservationLimitExceeded {
98        /// Original descriptive ceiling, not spending authority.
99        limit: u32,
100        /// Reported actual calls.
101        reported: u32,
102    },
103}
104
105#[cfg(test)]
106mod tests;