use crate::error::{Error, Result};
use crate::sandbox::{LanguageSurface, Policy};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Ceiling(Policy);
impl Ceiling {
pub fn new(policy: Policy) -> Result<Self> {
if policy.language() == LanguageSurface::Full {
return Err(Error::CeilingUnbounded {
reason: "language surface is full",
});
}
if policy.grants().is_unrestricted() {
return Err(Error::CeilingUnbounded {
reason: "grants are unrestricted",
});
}
Ok(Self(policy))
}
#[must_use]
pub const fn policy(&self) -> &Policy {
&self.0
}
}
#[cfg(test)]
mod tests {
#![expect(
clippy::unwrap_used,
reason = "tests unwrap known-valid fixtures; a panic is the intended failure signal"
)]
use super::Ceiling;
use crate::{GrantSet, LanguageSurface, Policy};
#[test]
fn confined_and_pure_are_ceilings() {
assert!(Ceiling::new(Policy::confined()).is_ok());
assert!(Ceiling::new(Policy::pure()).is_ok());
}
#[test]
fn trusted_is_refused_for_its_grants_and_its_language() {
let err = Ceiling::new(Policy::trusted()).unwrap_err();
assert!(err.to_string().contains("language surface"), "{err}");
let declared_but_full = Policy::trusted().with_grants(GrantSet::declared());
let err = Ceiling::new(declared_but_full).unwrap_err();
assert!(err.to_string().contains("language surface"), "{err}");
let restricted_but_unrestricted = Policy::confined()
.with_language(LanguageSurface::Restricted)
.with_grants(GrantSet::unrestricted());
let err = Ceiling::new(restricted_but_unrestricted).unwrap_err();
assert!(err.to_string().contains("unrestricted"), "{err}");
}
#[test]
fn a_ceiling_hands_back_the_policy_it_was_built_from() {
let policy = Policy::confined();
assert_eq!(Ceiling::new(policy.clone()).unwrap().policy(), &policy);
}
}