lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

service.rs (9972B)


      1 use std::collections::BTreeMap;
      2 
      3 use radroots_runtime_paths::ServiceId;
      4 use serde::Deserialize;
      5 
      6 /// Instance cardinality supported by a hardened service target.
      7 #[derive(Debug, Clone, Copy, Deserialize, PartialEq, Eq)]
      8 #[serde(rename_all = "snake_case")]
      9 pub enum ServiceInstanceSupport {
     10     Multiple,
     11 }
     12 
     13 /// Configuration document format supported by a hardened service target.
     14 #[derive(Debug, Clone, Copy, Deserialize, PartialEq, Eq)]
     15 #[serde(rename_all = "snake_case")]
     16 pub enum ServiceConfigurationFormat {
     17     Toml,
     18 }
     19 
     20 impl ServiceConfigurationFormat {
     21     #[must_use]
     22     pub const fn as_str(self) -> &'static str {
     23         match self {
     24             Self::Toml => "toml",
     25         }
     26     }
     27 }
     28 
     29 /// State initialization policy supported by a hardened service target.
     30 #[derive(Debug, Clone, Copy, Deserialize, PartialEq, Eq)]
     31 #[serde(rename_all = "snake_case")]
     32 pub enum ServiceStateInitialization {
     33     Explicit,
     34 }
     35 
     36 /// Daemon state-open policy supported by a hardened service target.
     37 #[derive(Debug, Clone, Copy, Deserialize, PartialEq, Eq)]
     38 #[serde(rename_all = "snake_case")]
     39 pub enum ServiceRunStatePolicy {
     40     ExistingOnly,
     41 }
     42 
     43 /// Detailed local-administration transport supported by a hardened service.
     44 #[derive(Debug, Clone, Copy, Deserialize, PartialEq, Eq)]
     45 #[serde(rename_all = "snake_case")]
     46 pub enum ServiceAdminTransport {
     47     Http11OverUnixDomainSocket,
     48 }
     49 
     50 /// Versioned base path for detailed local administration.
     51 #[derive(Debug, Clone, Copy, Deserialize, PartialEq, Eq)]
     52 pub enum ServiceAdminBasePath {
     53     #[serde(rename = "/v1")]
     54     V1,
     55 }
     56 
     57 /// Detailed status surface supported by a hardened service.
     58 #[derive(Debug, Clone, Copy, Deserialize, PartialEq, Eq)]
     59 #[serde(rename_all = "snake_case")]
     60 pub enum ServiceStatusSurface {
     61     LocalAdminServiceStatusV1,
     62 }
     63 
     64 /// Public operations surface supported by a hardened service.
     65 #[derive(Debug, Clone, Copy, Deserialize, PartialEq, Eq)]
     66 #[serde(rename_all = "snake_case")]
     67 pub enum ServiceOperationsSurface {
     68     CachedLivezReadyzMetrics,
     69 }
     70 
     71 impl ServiceOperationsSurface {
     72     pub const ROUTES: [&str; 3] = ["/livez", "/readyz", "/metrics"];
     73 
     74     #[must_use]
     75     pub const fn routes(self) -> [&'static str; 3] {
     76         match self {
     77             Self::CachedLivezReadyzMetrics => Self::ROUTES,
     78         }
     79     }
     80 }
     81 
     82 /// Current evidence posture for an eligible service target.
     83 #[derive(Debug, Clone, Copy, Deserialize, PartialEq, Eq)]
     84 #[serde(rename_all = "snake_case")]
     85 pub enum ServiceSupportPosture {
     86     Target,
     87 }
     88 
     89 /// Exact Linux target triples eligible for future Tier-1 qualification.
     90 #[derive(Debug, Clone, Copy, Deserialize, PartialEq, Eq)]
     91 pub enum ServiceTier1Target {
     92     #[serde(rename = "x86_64-unknown-linux-gnu")]
     93     X86_64UnknownLinuxGnu,
     94     #[serde(rename = "aarch64-unknown-linux-gnu")]
     95     Aarch64UnknownLinuxGnu,
     96 }
     97 
     98 impl ServiceTier1Target {
     99     pub const ALL: [Self; 2] = [Self::X86_64UnknownLinuxGnu, Self::Aarch64UnknownLinuxGnu];
    100 
    101     #[must_use]
    102     pub const fn as_str(self) -> &'static str {
    103         match self {
    104             Self::X86_64UnknownLinuxGnu => "x86_64-unknown-linux-gnu",
    105             Self::Aarch64UnknownLinuxGnu => "aarch64-unknown-linux-gnu",
    106         }
    107     }
    108 
    109     pub(crate) fn parse(value: &str) -> Option<Self> {
    110         Self::ALL
    111             .into_iter()
    112             .find(|target| target.as_str() == value)
    113     }
    114 }
    115 
    116 /// Closed metadata for one hardened standalone service target.
    117 #[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
    118 #[serde(try_from = "HardenedServiceTargetWire")]
    119 pub struct HardenedServiceTarget {
    120     service_id: ServiceId,
    121     instance_support: ServiceInstanceSupport,
    122     config_format: ServiceConfigurationFormat,
    123     state_initialization: ServiceStateInitialization,
    124     run_state_policy: ServiceRunStatePolicy,
    125     admin_transport: ServiceAdminTransport,
    126     admin_base_path: ServiceAdminBasePath,
    127     admin_contract_version: u32,
    128     status_surface: ServiceStatusSurface,
    129     operations_surface: ServiceOperationsSurface,
    130     support_posture: ServiceSupportPosture,
    131     tier_1_targets: Vec<ServiceTier1Target>,
    132 }
    133 
    134 #[derive(Deserialize)]
    135 #[serde(deny_unknown_fields)]
    136 struct HardenedServiceTargetWire {
    137     service_id: ServiceId,
    138     instance_support: ServiceInstanceSupport,
    139     config_format: ServiceConfigurationFormat,
    140     state_initialization: ServiceStateInitialization,
    141     run_state_policy: ServiceRunStatePolicy,
    142     admin_transport: ServiceAdminTransport,
    143     admin_base_path: ServiceAdminBasePath,
    144     admin_contract_version: u32,
    145     status_surface: ServiceStatusSurface,
    146     operations_surface: ServiceOperationsSurface,
    147     support_posture: ServiceSupportPosture,
    148     tier_1_targets: Vec<ServiceTier1Target>,
    149 }
    150 
    151 impl HardenedServiceTarget {
    152     #[must_use]
    153     pub fn service_id(&self) -> &ServiceId {
    154         &self.service_id
    155     }
    156 
    157     #[must_use]
    158     pub const fn instance_support(&self) -> ServiceInstanceSupport {
    159         self.instance_support
    160     }
    161 
    162     #[must_use]
    163     pub const fn config_format(&self) -> ServiceConfigurationFormat {
    164         self.config_format
    165     }
    166 
    167     #[must_use]
    168     pub const fn state_initialization(&self) -> ServiceStateInitialization {
    169         self.state_initialization
    170     }
    171 
    172     #[must_use]
    173     pub const fn run_state_policy(&self) -> ServiceRunStatePolicy {
    174         self.run_state_policy
    175     }
    176 
    177     #[must_use]
    178     pub const fn admin_transport(&self) -> ServiceAdminTransport {
    179         self.admin_transport
    180     }
    181 
    182     #[must_use]
    183     pub const fn admin_base_path(&self) -> ServiceAdminBasePath {
    184         self.admin_base_path
    185     }
    186 
    187     #[must_use]
    188     pub const fn admin_contract_version(&self) -> u32 {
    189         self.admin_contract_version
    190     }
    191 
    192     #[must_use]
    193     pub const fn status_surface(&self) -> ServiceStatusSurface {
    194         self.status_surface
    195     }
    196 
    197     #[must_use]
    198     pub const fn operations_surface(&self) -> ServiceOperationsSurface {
    199         self.operations_surface
    200     }
    201 
    202     #[must_use]
    203     pub const fn support_posture(&self) -> ServiceSupportPosture {
    204         self.support_posture
    205     }
    206 
    207     #[must_use]
    208     pub fn tier_1_targets(&self) -> &[ServiceTier1Target] {
    209         &self.tier_1_targets
    210     }
    211 
    212     fn has_exact_common_contract(&self) -> bool {
    213         [
    214             self.instance_support == ServiceInstanceSupport::Multiple,
    215             self.config_format == ServiceConfigurationFormat::Toml,
    216             self.state_initialization == ServiceStateInitialization::Explicit,
    217             self.run_state_policy == ServiceRunStatePolicy::ExistingOnly,
    218             self.admin_transport == ServiceAdminTransport::Http11OverUnixDomainSocket,
    219             self.admin_base_path == ServiceAdminBasePath::V1,
    220             self.admin_contract_version == 1,
    221             self.status_surface == ServiceStatusSurface::LocalAdminServiceStatusV1,
    222             self.operations_surface == ServiceOperationsSurface::CachedLivezReadyzMetrics,
    223             self.support_posture == ServiceSupportPosture::Target,
    224             self.tier_1_targets == ServiceTier1Target::ALL,
    225         ]
    226         .into_iter()
    227         .all(core::convert::identity)
    228     }
    229 }
    230 
    231 impl TryFrom<HardenedServiceTargetWire> for HardenedServiceTarget {
    232     type Error = &'static str;
    233 
    234     fn try_from(wire: HardenedServiceTargetWire) -> Result<Self, Self::Error> {
    235         let target = Self {
    236             service_id: wire.service_id,
    237             instance_support: wire.instance_support,
    238             config_format: wire.config_format,
    239             state_initialization: wire.state_initialization,
    240             run_state_policy: wire.run_state_policy,
    241             admin_transport: wire.admin_transport,
    242             admin_base_path: wire.admin_base_path,
    243             admin_contract_version: wire.admin_contract_version,
    244             status_surface: wire.status_surface,
    245             operations_surface: wire.operations_surface,
    246             support_posture: wire.support_posture,
    247             tier_1_targets: wire.tier_1_targets,
    248         };
    249         if !matches!(target.service_id.as_str(), "myc" | "rhi")
    250             || !target.has_exact_common_contract()
    251         {
    252             return Err("hardened service target does not match the v1 contract");
    253         }
    254         Ok(target)
    255     }
    256 }
    257 
    258 /// Validated exact Myc/RHI service-target inventory.
    259 #[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
    260 #[serde(try_from = "BTreeMap<String, HardenedServiceTarget>")]
    261 pub struct HardenedServiceTargets(BTreeMap<String, HardenedServiceTarget>);
    262 
    263 impl HardenedServiceTargets {
    264     #[must_use]
    265     pub fn get(&self, service_id: &ServiceId) -> Option<&HardenedServiceTarget> {
    266         self.0.get(service_id.as_str())
    267     }
    268 
    269     pub fn iter(&self) -> impl ExactSizeIterator<Item = (&str, &HardenedServiceTarget)> {
    270         self.0.iter().map(|(key, value)| (key.as_str(), value))
    271     }
    272 
    273     #[must_use]
    274     pub fn len(&self) -> usize {
    275         self.0.len()
    276     }
    277 
    278     #[must_use]
    279     pub fn is_empty(&self) -> bool {
    280         self.0.is_empty()
    281     }
    282 }
    283 
    284 impl TryFrom<BTreeMap<String, HardenedServiceTarget>> for HardenedServiceTargets {
    285     type Error = &'static str;
    286 
    287     fn try_from(targets: BTreeMap<String, HardenedServiceTarget>) -> Result<Self, Self::Error> {
    288         const REQUIRED_SERVICES: [&str; 2] = ["myc", "rhi"];
    289 
    290         if targets.len() != REQUIRED_SERVICES.len() {
    291             return Err("hardened service target inventory must contain exactly Myc and RHI");
    292         }
    293         for service in REQUIRED_SERVICES {
    294             let Some(target) = targets.get(service) else {
    295                 return Err("hardened service target inventory is incomplete");
    296             };
    297             if target.service_id.as_str() != service || !target.has_exact_common_contract() {
    298                 return Err("hardened service target metadata does not match the v1 contract");
    299             }
    300         }
    301         if targets
    302             .iter()
    303             .any(|(key, target)| key != target.service_id.as_str())
    304         {
    305             return Err("hardened service target key does not match its service identifier");
    306         }
    307 
    308         Ok(Self(targets))
    309     }
    310 }