ic_backup/policy/ic_observation/
mod.rs1use crate::model::{
4 attempt_journal::AttemptJournalRecord,
5 ic_lifecycle_reply::{IcLifecycleReply, IcLifecycleReplyError},
6 ic_observation::{IcObservationRequest, IcObservationRequestError, IcObservationResponse},
7 ic_request::IcManagementMethodRecord,
8 ic_snapshot_reply::{IcSnapshotReply, IcSnapshotReplyError},
9};
10use thiserror::Error;
11
12#[derive(Debug)]
14pub enum IcObservationReplyView<'a> {
15 Inventory(IcSnapshotReply<'a>),
17 Status(IcLifecycleReply<'a>),
19}
20
21#[derive(Debug)]
23pub struct IcObservationResponseView<'a> {
24 response: &'a IcObservationResponse,
25 reply: IcObservationReplyView<'a>,
26}
27impl<'a> IcObservationResponseView<'a> {
28 #[must_use]
30 pub const fn response(&self) -> &'a IcObservationResponse {
31 self.response
32 }
33 #[must_use]
35 pub const fn reply(&self) -> &IcObservationReplyView<'a> {
36 &self.reply
37 }
38}
39
40pub fn validate_response<'a>(
50 request: &IcObservationRequest<'a>,
51 journal: &AttemptJournalRecord,
52 response: &'a IcObservationResponse,
53) -> Result<IcObservationResponseView<'a>, IcObservationAssociationError> {
54 request.validate_journal(journal)?;
55 let input = response.input();
56 if input.authority != request.authority().digest() {
57 return Err(IcObservationAssociationError::AuthorityMismatch);
58 }
59 if input.mutation_attempt != request.mutation_attempt()
60 || input.observation_attempt != request.observation_attempt()
61 {
62 return Err(IcObservationAssociationError::AttemptMismatch);
63 }
64 if input.request != request.payload().digest() {
65 return Err(IcObservationAssociationError::RequestMismatch);
66 }
67 if &input.context != request.plan().context() {
68 return Err(IcObservationAssociationError::ContextMismatch);
69 }
70 if input.target != request.payload().target() {
71 return Err(IcObservationAssociationError::TargetMismatch);
72 }
73 let reply = match request.payload().method() {
74 IcManagementMethodRecord::ListCanisterSnapshots => IcObservationReplyView::Inventory(
75 IcSnapshotReply::decode(request.payload(), &input.reply)?,
76 ),
77 _ => IcObservationReplyView::Status(IcLifecycleReply::decode(
79 request.payload(),
80 &input.reply,
81 )?),
82 };
83 Ok(IcObservationResponseView { response, reply })
84}
85
86#[derive(Debug, Error)]
88pub enum IcObservationAssociationError {
89 #[error(transparent)]
91 Reservation(#[from] IcObservationRequestError),
92 #[error("IC observation response authority mismatch")]
94 AuthorityMismatch,
95 #[error("IC observation response attempt mismatch")]
97 AttemptMismatch,
98 #[error("IC observation response request mismatch")]
100 RequestMismatch,
101 #[error("IC observation response context mismatch")]
103 ContextMismatch,
104 #[error("IC observation response target mismatch")]
106 TargetMismatch,
107 #[error(transparent)]
109 Inventory(#[from] IcSnapshotReplyError),
110 #[error(transparent)]
112 Status(#[from] IcLifecycleReplyError),
113}
114
115#[cfg(test)]
116mod tests;