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    let binding = request.binding();
57    super::observed_context::admit_request_context(
58        &digest,
59        observation.request(),
60        binding,
61        observation.context(),
62        ControlAuthorityError::RequestMismatch,
63        ControlAuthorityError::ContextMismatch,
64    )?;
65    super::observed_context::admit_target_limit(
66        binding,
67        observation.target(),
68        request.max_remote_observations(),
69        observation.remote_observations(),
70        ControlAuthorityError::TargetMismatch,
71        |limit, reported| ControlAuthorityError::ObservationLimitExceeded { limit, reported },
72    )?;
73    if !observation.controllers().contains_caller(binding) {
74        return Err(ControlAuthorityError::CallerNotController);
75    }
76    Ok(ControlAuthorityView {
77        request: digest,
78        observation,
79    })
80}
81/// Typed denial; no mismatch changes a plan/journal or admits any paid effect.
82#[derive(Debug, Eq, Error, PartialEq)]
83pub enum ControlAuthorityError {
84    /// Original intent/operation/payload/challenge/ceiling differs.
85    #[error("control observation request mismatch")]
86    RequestMismatch,
87    /// Actually observed context differs.
88    #[error("control observed {0} mismatch")]
89    ContextMismatch(&'static str),
90    /// Actually observed target differs.
91    #[error("control observed target mismatch")]
92    TargetMismatch,
93    /// Exact selected caller is absent; other access does not grant this lane.
94    #[error("selected caller is not an observed controller")]
95    CallerNotController,
96    /// Actual reported remote calls exceed the descriptive ceiling.
97    #[error("control reports {reported} observations above ceiling {limit}")]
98    ObservationLimitExceeded {
99        /// Original descriptive ceiling, not spending authority.
100        limit: u32,
101        /// Reported actual calls.
102        reported: u32,
103    },
104}
105
106#[cfg(test)]
107mod tests;