ic_backup/policy/membership/
mod.rs1use crate::model::{
4 artifacts::ArtifactChecksumRecord,
5 inventory::InventoryRecord,
6 membership::{MembershipObservation, MembershipObservationRequest},
7};
8use thiserror::Error;
9
10#[derive(Clone, Debug)]
12pub struct MembershipView<'a> {
13 observation: &'a MembershipObservation,
14 selected_targets: &'a [String],
15}
16
17impl MembershipView<'_> {
18 #[must_use]
20 pub const fn request(&self) -> &ArtifactChecksumRecord {
21 &self.observation.request
22 }
23 #[must_use]
25 pub const fn inventory(&self) -> &InventoryRecord {
26 &self.observation.inventory
27 }
28 #[must_use]
30 pub const fn selected_targets(&self) -> &[String] {
31 self.selected_targets
32 }
33 #[must_use]
35 pub const fn revision(&self) -> Option<&ArtifactChecksumRecord> {
36 self.observation.revision.as_ref()
37 }
38 #[must_use]
40 pub const fn evidence(&self) -> &ArtifactChecksumRecord {
41 &self.observation.evidence
42 }
43 #[must_use]
45 pub const fn remote_observations(&self) -> u32 {
46 self.observation.remote_observations
47 }
48}
49
50pub fn validate<'a>(
58 request: &'a MembershipObservationRequest<'_>,
59 observation: &'a MembershipObservation,
60) -> Result<MembershipView<'a>, MembershipError> {
61 let digest = request.digest();
62 let binding = request.binding();
63 super::observed_context::admit_request_context(
64 &digest,
65 &observation.request,
66 binding,
67 &observation.context,
68 MembershipError::RequestMismatch,
69 MembershipError::ContextMismatch,
70 )?;
71 if observation.inventory != *request.inventory() {
72 return Err(MembershipError::InventoryMismatch);
73 }
74 super::observed_context::admit_limit(
75 request.max_remote_observations(),
76 observation.remote_observations,
77 |limit, reported| MembershipError::ObservationLimitExceeded { limit, reported },
78 )?;
79 Ok(MembershipView {
80 observation,
81 selected_targets: request.selected_targets(),
82 })
83}
84
85#[derive(Debug, Eq, Error, PartialEq)]
87pub enum MembershipError {
88 #[error("membership request identity mismatch")]
90 RequestMismatch,
91 #[error("membership observed {0} mismatch")]
93 ContextMismatch(&'static str),
94 #[error("membership inventory mismatch")]
96 InventoryMismatch,
97 #[error("membership reports {reported} observations above ceiling {limit}")]
99 ObservationLimitExceeded {
100 limit: u32,
102 reported: u32,
104 },
105}
106
107#[cfg(test)]
108mod tests;