use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum EvidenceTier {
HostFact,
Constrained,
SelfReport,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Fact {
pub tier: EvidenceTier,
pub name: String,
pub value: String,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct Evidence {
pub facts: Vec<Fact>,
}
impl Evidence {
pub fn push(&mut self, tier: EvidenceTier, name: &str, value: String) {
self.facts.push(Fact {
tier,
name: name.to_string(),
value,
});
}
pub fn host_fact(&mut self, name: &str, value: String) {
self.push(EvidenceTier::HostFact, name, value);
}
pub fn constrained(&mut self, name: &str, value: String) {
self.push(EvidenceTier::Constrained, name, value);
}
pub fn self_report(&mut self, name: &str, value: String) {
self.push(EvidenceTier::SelfReport, name, value);
}
pub fn has_host_fact(&self) -> bool {
self.facts.iter().any(|f| f.tier == EvidenceTier::HostFact)
}
pub fn host_fact_value(&self, name: &str) -> Option<&str> {
self.facts
.iter()
.find(|f| f.tier == EvidenceTier::HostFact && f.name == name)
.map(|f| f.value.as_str())
}
}
#[cfg(test)]
mod evidence_tests {
use super::*;
#[test]
fn pass_requires_host_fact() {
let mut e = Evidence::default();
e.self_report("marker", "PASS".to_string());
e.constrained("errno", "EACCES".to_string());
assert!(!e.has_host_fact());
e.host_fact("postmortem", "absent".to_string());
assert!(e.has_host_fact());
}
}