use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum OutsideProjectPolicy {
ReadOnly,
DenyAll,
AllowAll,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
pub struct GovernanceConfig {
#[serde(default, alias = "outsideProject", skip_serializing_if = "Option::is_none")]
pub outside_project: Option<OutsideProjectPolicy>,
}
impl GovernanceConfig {
pub fn effective_outside_project(&self, is_user_profile: bool) -> OutsideProjectPolicy {
self.outside_project
.unwrap_or_else(|| default_outside_policy(is_user_profile))
}
}
pub fn default_outside_policy(is_user_profile: bool) -> OutsideProjectPolicy {
if is_user_profile {
OutsideProjectPolicy::ReadOnly
} else {
OutsideProjectPolicy::AllowAll
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::config::KernelConfig;
#[test]
fn default_is_profile_keyed() {
let g = KernelConfig::default().governance;
assert_eq!(g.outside_project, None);
assert_eq!(g.effective_outside_project(true), OutsideProjectPolicy::ReadOnly);
assert_eq!(g.effective_outside_project(false), OutsideProjectPolicy::AllowAll);
let k: KernelConfig = serde_json::from_str("{}").unwrap();
assert_eq!(k.governance, g);
}
#[test]
fn explicit_policy_wins_on_every_profile() {
let g = GovernanceConfig { outside_project: Some(OutsideProjectPolicy::DenyAll) };
assert_eq!(g.effective_outside_project(true), OutsideProjectPolicy::DenyAll);
assert_eq!(g.effective_outside_project(false), OutsideProjectPolicy::DenyAll);
}
#[test]
fn parses_each_named_policy() {
for (s, want) in [
("read_only", OutsideProjectPolicy::ReadOnly),
("deny_all", OutsideProjectPolicy::DenyAll),
("allow_all", OutsideProjectPolicy::AllowAll),
] {
let k: KernelConfig =
serde_json::from_str(&format!(r#"{{"governance":{{"outside_project":"{s}"}}}}"#))
.unwrap();
assert_eq!(k.governance.outside_project, Some(want));
}
assert!(
serde_json::from_str::<KernelConfig>(r#"{"governance":{"outside_project":"x"}}"#)
.is_err()
);
}
}