Skip to main content

spatialrust_platform/
security.rs

1//! Security audit checklist items.
2
3/// One security audit checklist item.
4#[derive(Clone, Debug, PartialEq, Eq)]
5pub struct SecurityAuditItem {
6    /// Item id.
7    pub id: String,
8    /// Description.
9    pub description: String,
10    /// Whether the item is currently satisfied.
11    pub satisfied: bool,
12}
13
14/// Security checklist for release gates.
15#[derive(Clone, Debug, Default, PartialEq, Eq)]
16pub struct SecurityChecklist {
17    items: Vec<SecurityAuditItem>,
18}
19
20impl SecurityChecklist {
21    /// Creates an empty checklist.
22    #[must_use]
23    pub fn new() -> Self {
24        Self::default()
25    }
26
27    /// Adds an item.
28    pub fn push(&mut self, id: impl Into<String>, description: impl Into<String>, satisfied: bool) {
29        self.items.push(SecurityAuditItem {
30            id: id.into(),
31            description: description.into(),
32            satisfied,
33        });
34    }
35
36    /// Marks an existing item satisfied by id.
37    pub fn mark_satisfied(&mut self, id: &str) -> bool {
38        if let Some(item) = self.items.iter_mut().find(|item| item.id == id) {
39            item.satisfied = true;
40            true
41        } else {
42            false
43        }
44    }
45
46    /// Returns whether every item is satisfied.
47    #[must_use]
48    pub fn all_satisfied(&self) -> bool {
49        !self.items.is_empty() && self.items.iter().all(|item| item.satisfied)
50    }
51
52    /// Returns unsatisfied item ids.
53    #[must_use]
54    pub fn unsatisfied_ids(&self) -> Vec<&str> {
55        self.items.iter().filter(|item| !item.satisfied).map(|item| item.id.as_str()).collect()
56    }
57
58    /// Returns items.
59    #[must_use]
60    pub fn items(&self) -> &[SecurityAuditItem] {
61        &self.items
62    }
63
64    /// Baseline checklist for north-star release gates (initially unsatisfied).
65    #[must_use]
66    pub fn north_star_baseline() -> Self {
67        let mut checklist = Self::new();
68        checklist.push(
69            "no-silent-device-copies",
70            "Production APIs never perform implicit host/device copies",
71            false,
72        );
73        checklist.push(
74            "no-secrets-in-fixtures",
75            "Repository fixtures contain no private keys or customer sensor dumps",
76            false,
77        );
78        checklist.push(
79            "feature-gated-heavy-runtimes",
80            "ONNX/ROS2/CUDA/OpenUSD native deps remain opt-in features",
81            false,
82        );
83        checklist.push(
84            "deny-unsafe-public-surface",
85            "Public crates keep #![deny(unsafe_code)] outside audited FFI/GPU boundaries",
86            false,
87        );
88        checklist
89    }
90
91    /// Satisfied copy of [`Self::north_star_baseline`] for integration proofs.
92    #[must_use]
93    pub fn north_star_baseline_satisfied() -> Self {
94        let mut checklist = Self::north_star_baseline();
95        for item in &mut checklist.items {
96            item.satisfied = true;
97        }
98        checklist
99    }
100}
101
102#[cfg(test)]
103mod tests {
104    use super::SecurityChecklist;
105
106    #[test]
107    fn baseline_starts_unsatisfied() {
108        let checklist = SecurityChecklist::north_star_baseline();
109        assert!(!checklist.all_satisfied());
110        assert_eq!(checklist.unsatisfied_ids().len(), 4);
111        assert!(SecurityChecklist::north_star_baseline_satisfied().all_satisfied());
112    }
113}