use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ProducerTrust {
PinnedDigest,
VendorAsserted,
}
impl ProducerTrust {
#[must_use]
pub fn as_str(self) -> &'static str {
match self {
Self::PinnedDigest => "pinned_digest",
Self::VendorAsserted => "vendor_asserted",
}
}
#[must_use]
pub fn is_verifiable(self) -> bool {
matches!(self, Self::PinnedDigest)
}
#[must_use]
pub fn caveat(self) -> Option<&'static str> {
match self {
Self::PinnedDigest => None,
Self::VendorAsserted => Some(
"this identity is a claim, not a measurement: a vendor model string is a \
mutable pointer, so the weights behind it can change while the name does \
not, and Roteiro cannot detect that",
),
}
}
}
impl std::fmt::Display for ProducerTrust {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
#[cfg(test)]
mod tests {
use super::ProducerTrust;
#[test]
fn a_vendor_asserted_identity_declares_itself_a_claim() {
let trust = ProducerTrust::VendorAsserted;
assert!(!trust.is_verifiable());
let caveat = trust
.caveat()
.expect("a vendor-asserted record carries a caveat");
assert!(caveat.contains("mutable pointer"), "{caveat}");
assert!(caveat.contains("cannot detect"), "{caveat}");
}
#[test]
fn a_pinned_digest_needs_no_caveat_and_renders_differently() {
assert!(ProducerTrust::PinnedDigest.is_verifiable());
assert!(ProducerTrust::PinnedDigest.caveat().is_none());
assert_ne!(
ProducerTrust::PinnedDigest.as_str(),
ProducerTrust::VendorAsserted.as_str()
);
}
#[test]
fn the_token_round_trips_through_serde() {
for trust in [ProducerTrust::PinnedDigest, ProducerTrust::VendorAsserted] {
let json = serde_json::to_string(&trust).expect("serialize");
assert_eq!(json, format!("\"{}\"", trust.as_str()));
let back: ProducerTrust = serde_json::from_str(&json).expect("deserialize");
assert_eq!(back, trust);
}
}
}