ic_backup/policy/control_authority/
mod.rs1use crate::model::{
4 artifacts::ArtifactChecksumRecord,
5 control_authority::{ControlObservation, ControlObservationRequest, ControllerSet},
6};
7use thiserror::Error;
8
9#[derive(Clone, Debug)]
11pub struct ControlAuthorityView<'a> {
12 request: ArtifactChecksumRecord,
13 observation: &'a ControlObservation,
14}
15impl ControlAuthorityView<'_> {
16 #[must_use]
18 pub const fn request(&self) -> &ArtifactChecksumRecord {
19 &self.request
20 }
21 #[must_use]
23 pub fn target(&self) -> &str {
24 self.observation.target()
25 }
26 #[must_use]
28 pub const fn controllers(&self) -> &ControllerSet {
29 self.observation.controllers()
30 }
31 #[must_use]
33 pub const fn evidence(&self) -> &ArtifactChecksumRecord {
34 self.observation.evidence()
35 }
36 #[must_use]
38 pub const fn remote_observations(&self) -> u32 {
39 self.observation.remote_observations()
40 }
41}
42pub 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#[derive(Debug, Eq, Error, PartialEq)]
83pub enum ControlAuthorityError {
84 #[error("control observation request mismatch")]
86 RequestMismatch,
87 #[error("control observed {0} mismatch")]
89 ContextMismatch(&'static str),
90 #[error("control observed target mismatch")]
92 TargetMismatch,
93 #[error("selected caller is not an observed controller")]
95 CallerNotController,
96 #[error("control reports {reported} observations above ceiling {limit}")]
98 ObservationLimitExceeded {
99 limit: u32,
101 reported: u32,
103 },
104}
105
106#[cfg(test)]
107mod tests;