use crate::model::{
artifacts::ArtifactChecksumRecord,
control_authority::{ControlObservation, ControlObservationRequest, ControllerSet},
};
use thiserror::Error;
#[derive(Clone, Debug)]
pub struct ControlAuthorityView<'a> {
request: ArtifactChecksumRecord,
observation: &'a ControlObservation,
}
impl ControlAuthorityView<'_> {
#[must_use]
pub const fn request(&self) -> &ArtifactChecksumRecord {
&self.request
}
#[must_use]
pub fn target(&self) -> &str {
self.observation.target()
}
#[must_use]
pub const fn controllers(&self) -> &ControllerSet {
self.observation.controllers()
}
#[must_use]
pub const fn evidence(&self) -> &ArtifactChecksumRecord {
self.observation.evidence()
}
#[must_use]
pub const fn remote_observations(&self) -> u32 {
self.observation.remote_observations()
}
}
pub fn validate<'a>(
request: &ControlObservationRequest<'_>,
observation: &'a ControlObservation,
) -> Result<ControlAuthorityView<'a>, ControlAuthorityError> {
let digest = request.digest();
let binding = request.binding();
super::observed_context::admit_request_context(
&digest,
observation.request(),
binding,
observation.context(),
ControlAuthorityError::RequestMismatch,
ControlAuthorityError::ContextMismatch,
)?;
super::observed_context::admit_target_limit(
binding,
observation.target(),
request.max_remote_observations(),
observation.remote_observations(),
ControlAuthorityError::TargetMismatch,
|limit, reported| ControlAuthorityError::ObservationLimitExceeded { limit, reported },
)?;
if !observation.controllers().contains_caller(binding) {
return Err(ControlAuthorityError::CallerNotController);
}
Ok(ControlAuthorityView {
request: digest,
observation,
})
}
#[derive(Debug, Eq, Error, PartialEq)]
pub enum ControlAuthorityError {
#[error("control observation request mismatch")]
RequestMismatch,
#[error("control observed {0} mismatch")]
ContextMismatch(&'static str),
#[error("control observed target mismatch")]
TargetMismatch,
#[error("selected caller is not an observed controller")]
CallerNotController,
#[error("control reports {reported} observations above ceiling {limit}")]
ObservationLimitExceeded {
limit: u32,
reported: u32,
},
}
#[cfg(test)]
mod tests;