use handlebars::Handlebars;
use lazy_static::lazy_static;
use serde::Deserialize;
use std::{collections::HashMap, str};
use crate::{
contrib::handlebars::{fs_read_to_string_helper, os_env_helper, os_homedir_helper},
Executor, File, Limits, Mount, Result, Seccomp,
};
lazy_static! {
static ref SANDBOX_POLICY_HANDLEBARS: Handlebars<'static> = {
let mut handlebars = Handlebars::new();
handlebars.register_helper("fs_read_to_string", Box::new(fs_read_to_string_helper));
handlebars.register_helper("os_env", Box::new(os_env_helper));
handlebars.register_helper("os_homedir", Box::new(os_homedir_helper));
handlebars
};
}
#[derive(Deserialize, Default, Debug)]
#[serde(deny_unknown_fields)]
pub struct SandboxPolicy {
share_net: Option<bool>,
share_uts: Option<bool>,
uid: Option<u32>,
gid: Option<u32>,
hostname: Option<String>,
#[serde(default)]
mounts: Vec<Mount>,
#[serde(default)]
files: Vec<File>,
#[serde(default)]
env: HashMap<String, String>,
#[serde(default)]
limits: Limits,
#[serde(default)]
seccomp: Option<Seccomp>,
}
impl SandboxPolicy {
#[allow(clippy::should_implement_trait)]
pub fn from_str(data: &str) -> Result<Self> {
let data = SANDBOX_POLICY_HANDLEBARS.render_template(data, &())?;
let policy: Self = toml::from_str(&data)?;
Ok(policy)
}
}
#[derive(Default)]
pub struct Sandbox {
policy: Option<SandboxPolicy>,
}
impl Sandbox {
pub fn new() -> Self {
Self {
..Default::default()
}
}
pub fn with_policy(&mut self, policy: SandboxPolicy) -> &mut Self {
self.policy = Some(policy);
self
}
pub fn command<SA: AsRef<str>>(&self, prog: &str, argv: &[SA]) -> Executor {
let mut executor = Executor::new(prog, argv);
let policy = match &self.policy {
Some(val) => val,
None => return executor,
};
if let Some(share) = policy.share_net {
executor.share_net_ns(share);
}
if let Some(share) = policy.share_uts {
executor.share_uts_ns(share);
}
if let Some(id) = policy.uid {
executor.uid(id);
}
if let Some(id) = policy.gid {
executor.gid(id);
}
if let Some(hostname) = &policy.hostname {
executor.hostname(hostname);
}
executor.mounts(&policy.mounts);
executor.files(&policy.files);
for (k, v) in policy.env.iter() {
executor.setenv(k, v);
}
executor.limits(&policy.limits);
executor.seccomp(&policy.seccomp);
executor
}
}