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