use std::marker::PhantomData;
use serde::{Serialize, Deserialize};
pub trait Policy: Sized + Send + Sync + 'static {
fn name() -> &'static str;
fn requires_determinism() -> bool;
fn allows_network() -> bool;
fn allows_root() -> bool;
fn allows_real_fs() -> bool;
fn security_level() -> u8;
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct Locked;
impl Policy for Locked {
fn name() -> &'static str {
"Locked"
}
fn requires_determinism() -> bool {
true
}
fn allows_network() -> bool {
false
}
fn allows_root() -> bool {
false
}
fn allows_real_fs() -> bool {
false
}
fn security_level() -> u8 {
100
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct Permissive;
impl Policy for Permissive {
fn name() -> &'static str {
"Permissive"
}
fn requires_determinism() -> bool {
false
}
fn allows_network() -> bool {
true
}
fn allows_root() -> bool {
true
}
fn allows_real_fs() -> bool {
true
}
fn security_level() -> u8 {
30
}
}
pub struct PolicyValidator<P: Policy> {
_policy: PhantomData<P>,
}
impl<P: Policy> PolicyValidator<P> {
pub fn new() -> Self {
Self {
_policy: PhantomData,
}
}
pub fn validate_surfaces(&self, surfaces: &super::surfaces::DeterministicSurfaces) -> Result<(), String> {
if P::requires_determinism() && !surfaces.is_fully_deterministic() {
return Err(format!(
"Policy '{}' requires full determinism, but surfaces are not fully deterministic (score: {})",
P::name(),
surfaces.determinism_score()
));
}
if !P::allows_network() && matches!(surfaces.net_mode(), super::surfaces::NetMode::Real) {
return Err(format!(
"Policy '{}' does not allow network access, but network mode is Real",
P::name()
));
}
if !P::allows_real_fs() && matches!(surfaces.fs_mode(), super::surfaces::FsMode::Real) {
return Err(format!(
"Policy '{}' does not allow real filesystem access, but fs mode is Real",
P::name()
));
}
if !P::allows_root() && matches!(surfaces.proc_mode(), super::surfaces::ProcMode::Real) {
return Err(format!(
"Policy '{}' does not allow root process, but proc mode is Real",
P::name()
));
}
Ok(())
}
pub fn metadata(&self) -> PolicyMetadata {
PolicyMetadata {
name: P::name().to_string(),
requires_determinism: P::requires_determinism(),
allows_network: P::allows_network(),
allows_root: P::allows_root(),
allows_real_fs: P::allows_real_fs(),
security_level: P::security_level(),
}
}
}
impl<P: Policy> Default for PolicyValidator<P> {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PolicyMetadata {
pub name: String,
pub requires_determinism: bool,
pub allows_network: bool,
pub allows_root: bool,
pub allows_real_fs: bool,
pub security_level: u8,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::cleanroom::surfaces::DeterministicSurfaces;
#[test]
fn test_locked_policy() {
assert_eq!(Locked::name(), "Locked");
assert_eq!(Locked::security_level(), 100);
assert!(Locked::requires_determinism());
assert!(!Locked::allows_network());
assert!(!Locked::allows_root());
assert!(!Locked::allows_real_fs());
}
#[test]
fn test_permissive_policy() {
assert_eq!(Permissive::name(), "Permissive");
assert_eq!(Permissive::security_level(), 30);
assert!(!Permissive::requires_determinism());
assert!(Permissive::allows_network());
assert!(Permissive::allows_root());
assert!(Permissive::allows_real_fs());
}
#[test]
fn test_locked_validator_accepts_deterministic() {
let validator = PolicyValidator::<Locked>::new();
let surfaces = DeterministicSurfaces::deterministic(42);
assert!(validator.validate_surfaces(&surfaces).is_ok());
}
#[test]
fn test_locked_validator_rejects_permissive() {
let validator = PolicyValidator::<Locked>::new();
let surfaces = DeterministicSurfaces::permissive();
assert!(validator.validate_surfaces(&surfaces).is_err());
}
#[test]
fn test_permissive_validator_accepts_all() {
let validator = PolicyValidator::<Permissive>::new();
let surfaces = DeterministicSurfaces::permissive();
assert!(validator.validate_surfaces(&surfaces).is_ok());
let det_surfaces = DeterministicSurfaces::deterministic(42);
assert!(validator.validate_surfaces(&det_surfaces).is_ok());
}
#[test]
fn test_policy_metadata() {
let validator = PolicyValidator::<Locked>::new();
let metadata = validator.metadata();
assert_eq!(metadata.name, "Locked");
assert_eq!(metadata.security_level, 100);
assert!(metadata.requires_determinism);
}
}