chio_http_core/
evaluation.rs1use chio_kernel::SignedExecutionNonce;
4use serde::{Deserialize, Serialize};
5
6use crate::{GuardEvidence, HttpReceipt, Verdict};
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct EvaluateResponse {
20 pub verdict: Verdict,
21 pub receipt: HttpReceipt,
22 #[serde(default)]
23 pub evidence: Vec<GuardEvidence>,
24 #[serde(default, skip_serializing_if = "Option::is_none")]
28 pub execution_nonce: Option<SignedExecutionNonce>,
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct VerifyReceiptResponse {
34 pub signature_valid: bool,
35 pub signer_trusted: bool,
36 pub receipt_id_valid: bool,
37 pub parameter_hash_valid: bool,
38 pub receipt_kind: String,
39 pub boundary_class: String,
40 pub trust_level: String,
41 pub result: String,
42 pub authorized: bool,
43 pub signer_key_hex: String,
44 pub ok: bool,
45}
46
47impl VerifyReceiptResponse {
48 #[must_use]
49 pub fn from_http_receipt(receipt: &HttpReceipt, signer_trusted: bool) -> Self {
50 let signature_valid = receipt.verify_signature().unwrap_or(false);
51 let receipt_id_valid = receipt.receipt_id_valid().unwrap_or(false);
52 let parameter_hash_valid = is_lower_hex_64(&receipt.content_hash);
53 let semantic_valid = receipt.receipt_kind
54 == chio_core_types::receipt::kinds::ReceiptKind::MediatedDecision
55 && receipt.boundary_class == chio_core_types::receipt::kinds::BoundaryClass::Prevent
56 && receipt.observation_outcome.is_none()
57 && receipt.trust_level == chio_core_types::receipt::kinds::TrustLevel::Mediated;
58 let ok = signature_valid
59 && signer_trusted
60 && receipt_id_valid
61 && parameter_hash_valid
62 && semantic_valid;
63 let authorized = ok && receipt.verdict.is_allowed();
64
65 Self {
66 signature_valid,
67 signer_trusted,
68 receipt_id_valid,
69 parameter_hash_valid,
70 receipt_kind: receipt.receipt_kind.as_str().to_string(),
71 boundary_class: receipt.boundary_class.as_str().to_string(),
72 trust_level: receipt.trust_level.as_str().to_string(),
73 result: verdict_result(&receipt.verdict).to_string(),
74 authorized,
75 signer_key_hex: receipt.kernel_key.to_hex(),
76 ok,
77 }
78 }
79}
80
81fn is_lower_hex_64(value: &str) -> bool {
82 value.len() == 64
83 && value
84 .bytes()
85 .all(|byte| byte.is_ascii_digit() || (b'a'..=b'f').contains(&byte))
86}
87
88fn verdict_result(verdict: &Verdict) -> &'static str {
89 match verdict {
90 Verdict::Allow => "allow",
91 Verdict::Deny { .. } => "deny",
92 Verdict::Cancel { .. } => "cancelled",
93 Verdict::Incomplete { .. } => "incomplete",
94 }
95}
96
97#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
99#[serde(rename_all = "snake_case")]
100pub enum SidecarStatus {
101 Healthy,
102 Degraded,
103 Unhealthy,
104}
105
106#[derive(Debug, Clone, Serialize, Deserialize)]
108pub struct HealthResponse {
109 pub status: SidecarStatus,
110 pub version: String,
111 #[serde(default)]
113 pub receipt_backend: String,
114 #[serde(default)]
117 pub revocation_backend: String,
118}