Skip to main content

qualia_core_db/net/
disclosure.rs

1//! Network disclosure discipline for outbound connections.
2//!
3//! Enforces that no adapter driver can reach out to the internet without
4//! explicit, pre-registered consent for its recipient and purpose.
5
6use std::collections::HashMap;
7
8/// An outbound network endpoint that an adapter requires access to.
9#[derive(Debug, Clone, PartialEq, Eq, Hash)]
10pub struct RegisteredEndpoint {
11    pub url: String,
12    pub purpose: String,
13    pub trigger: String,
14}
15
16/// The registry controlling egress to external layers.
17pub struct NetworkDisclosureRegistry {
18    /// Maps adapter ID (e.g. "dem_adapter") to its permitted endpoints
19    allowed_endpoints: HashMap<String, Vec<RegisteredEndpoint>>,
20}
21
22impl NetworkDisclosureRegistry {
23    pub fn new() -> Self {
24        Self {
25            allowed_endpoints: HashMap::new(),
26        }
27    }
28
29    /// Registers a permitted endpoint for an adapter.
30    pub fn register_egress(&mut self, adapter_id: &str, url: &str, purpose: &str, trigger: &str) {
31        let entry = self
32            .allowed_endpoints
33            .entry(adapter_id.to_string())
34            .or_insert_with(Vec::new);
35        entry.push(RegisteredEndpoint {
36            url: url.to_string(),
37            purpose: purpose.to_string(),
38            trigger: trigger.to_string(),
39        });
40    }
41
42    /// Fail-closed check before initiating `reqwest` or `/proxy/fetch`.
43    ///
44    /// Returns true if the endpoint is registered, false otherwise.
45    pub fn check_egress_consent(&self, adapter_id: &str, target_url: &str) -> bool {
46        if let Some(endpoints) = self.allowed_endpoints.get(adapter_id) {
47            for ep in endpoints {
48                if target_url.starts_with(&ep.url) {
49                    return true;
50                }
51            }
52        }
53        false
54    }
55}
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60
61    #[test]
62    fn test_disclosure_registry() {
63        let mut registry = NetworkDisclosureRegistry::new();
64
65        registry.register_egress(
66            "dem_adapter",
67            "https://elevation.example.com",
68            "Fetch Cloud-Optimized GeoTIFF for terrain",
69            "User pans camera to quadrant",
70        );
71
72        // Exact match
73        assert!(registry.check_egress_consent("dem_adapter", "https://elevation.example.com"));
74        // Prefix match
75        assert!(registry.check_egress_consent(
76            "dem_adapter",
77            "https://elevation.example.com/tile/1/2/3.tif"
78        ));
79
80        // Unregistered endpoint for the adapter
81        assert!(!registry.check_egress_consent("dem_adapter", "https://tracker.example.com/log"));
82
83        // Unregistered adapter
84        assert!(!registry.check_egress_consent("unknown_adapter", "https://elevation.example.com"));
85    }
86}