lilo_rm_core/
isolation.rs1use std::fmt::{Display, Formatter};
2use std::str::FromStr;
3
4use serde::{Deserialize, Serialize};
5use thiserror::Error;
6
7#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
8#[serde(tag = "type", content = "payload", rename_all = "snake_case")]
9pub enum IsolationPolicy {
10 #[default]
11 Host,
12 Docker(IsolationProfile),
13}
14
15impl IsolationPolicy {
16 pub fn is_host(&self) -> bool {
17 matches!(self, Self::Host)
18 }
19}
20
21impl Display for IsolationPolicy {
22 fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
23 match self {
24 Self::Host => formatter.write_str("host"),
25 Self::Docker(profile) => {
26 formatter.write_str("docker")?;
27 if let Some(name) = &profile.name {
28 write!(formatter, ":{name}")?;
29 }
30 Ok(())
31 }
32 }
33 }
34}
35
36impl FromStr for IsolationPolicy {
37 type Err = IsolationPolicyParseError;
38
39 fn from_str(value: &str) -> Result<Self, Self::Err> {
40 match value {
41 "host" => Ok(Self::Host),
42 "docker" => Ok(Self::Docker(IsolationProfile::default())),
43 _ => parse_docker_profile(value),
44 }
45 }
46}
47
48fn parse_docker_profile(value: &str) -> Result<IsolationPolicy, IsolationPolicyParseError> {
49 let Some(profile) = value.strip_prefix("docker:") else {
50 return Err(IsolationPolicyParseError(value.to_owned()));
51 };
52 if profile.is_empty() {
53 return Err(IsolationPolicyParseError(value.to_owned()));
54 }
55 Ok(IsolationPolicy::Docker(IsolationProfile {
56 name: Some(profile.to_owned()),
57 }))
58}
59
60#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
61pub struct IsolationProfile {
62 #[serde(default, skip_serializing_if = "Option::is_none")]
63 pub name: Option<String>,
64}
65
66#[derive(Debug, Error)]
67#[error("invalid isolation policy {0}; expected host, docker, or docker:PROFILE")]
68pub struct IsolationPolicyParseError(pub String);
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73
74 #[test]
75 fn isolation_policy_parses_host_and_docker_profiles() {
76 assert_eq!(
77 "host".parse::<IsolationPolicy>().unwrap(),
78 IsolationPolicy::Host
79 );
80 assert_eq!(
81 "docker".parse::<IsolationPolicy>().unwrap(),
82 IsolationPolicy::Docker(IsolationProfile { name: None })
83 );
84 assert_eq!(
85 "docker:locked".parse::<IsolationPolicy>().unwrap(),
86 IsolationPolicy::Docker(IsolationProfile {
87 name: Some("locked".to_owned())
88 })
89 );
90 }
91
92 #[test]
93 fn isolation_policy_rejects_unknown_or_empty_profiles() {
94 for value in ["", "sandbox", "docker:"] {
95 assert!(
96 value.parse::<IsolationPolicy>().is_err(),
97 "accepted invalid isolation policy {value}"
98 );
99 }
100 }
101}