Skip to main content

canic_host/deployment_truth/model/safety/
mod.rs

1use super::inventory::DeploymentInventoryV1;
2use super::plan::{DeploymentIdentityV1, DeploymentPlanV1};
3use serde::{Deserialize, Serialize};
4
5///
6/// DeploymentDiffV1
7///
8#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
9pub struct DeploymentDiffV1 {
10    pub schema_version: u32,
11    pub plan_identity: DeploymentIdentityV1,
12    pub observed_identity: Option<DeploymentIdentityV1>,
13    pub artifact_diff: Vec<DiffItemV1>,
14    pub controller_diff: Vec<DiffItemV1>,
15    pub pool_diff: Vec<DiffItemV1>,
16    pub embedded_config_diff: Vec<DiffItemV1>,
17    pub module_hash_diff: Vec<DiffItemV1>,
18    pub verifier_readiness_diff: Vec<DiffItemV1>,
19    pub resume_safety: ResumeSafetyV1,
20    pub hard_failures: Vec<SafetyFindingV1>,
21    pub warnings: Vec<SafetyFindingV1>,
22    pub resumable_phases: Vec<String>,
23}
24
25///
26/// SafetyReportV1
27///
28#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
29pub struct SafetyReportV1 {
30    pub schema_version: u32,
31    pub report_id: String,
32    pub diff_id: Option<String>,
33    pub status: SafetyStatusV1,
34    pub summary: String,
35    pub hard_failures: Vec<SafetyFindingV1>,
36    pub warnings: Vec<SafetyFindingV1>,
37    pub next_actions: Vec<String>,
38}
39
40///
41/// DeploymentCheckV1
42///
43#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
44pub struct DeploymentCheckV1 {
45    pub schema_version: u32,
46    pub check_id: String,
47    pub plan: DeploymentPlanV1,
48    pub inventory: DeploymentInventoryV1,
49    pub diff: DeploymentDiffV1,
50    pub report: SafetyReportV1,
51}
52
53///
54/// DiffItemV1
55///
56#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
57pub struct DiffItemV1 {
58    pub category: String,
59    pub subject: String,
60    pub expected: Option<String>,
61    pub observed: Option<String>,
62    pub severity: SafetySeverityV1,
63}
64
65///
66/// ResumeSafetyV1
67///
68#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
69pub struct ResumeSafetyV1 {
70    pub status: SafetyStatusV1,
71    pub reasons: Vec<String>,
72}
73
74///
75/// SafetyFindingV1
76///
77#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
78pub struct SafetyFindingV1 {
79    pub code: String,
80    pub message: String,
81    pub severity: SafetySeverityV1,
82    pub subject: Option<String>,
83}
84
85///
86/// SafetyStatusV1
87///
88#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
89pub enum SafetyStatusV1 {
90    NotEvaluated,
91    Safe,
92    Warning,
93    Blocked,
94}
95
96impl SafetyStatusV1 {
97    #[must_use]
98    pub const fn label(self) -> &'static str {
99        match self {
100            Self::NotEvaluated => "not_evaluated",
101            Self::Safe => "safe",
102            Self::Warning => "warning",
103            Self::Blocked => "blocked",
104        }
105    }
106}
107
108///
109/// SafetySeverityV1
110///
111#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
112pub enum SafetySeverityV1 {
113    Info,
114    Warning,
115    HardFailure,
116}
117
118#[cfg(test)]
119mod tests {
120    use super::*;
121
122    #[test]
123    fn safety_status_owns_text_labels() {
124        assert_eq!(SafetyStatusV1::NotEvaluated.label(), "not_evaluated");
125        assert_eq!(SafetyStatusV1::Safe.label(), "safe");
126        assert_eq!(SafetyStatusV1::Warning.label(), "warning");
127        assert_eq!(SafetyStatusV1::Blocked.label(), "blocked");
128    }
129}