diff --git a/crates/molotov-bootstrap/src/lib.rs b/crates/molotov-bootstrap/src/lib.rs index 0f8afac..d6d21a8 100644 --- a/crates/molotov-bootstrap/src/lib.rs +++ b/crates/molotov-bootstrap/src/lib.rs @@ -4,3 +4,4 @@ pub mod cdn; pub mod error; pub mod fflags; pub mod mods; +pub mod sandbox; diff --git a/crates/molotov-bootstrap/src/sandbox.rs b/crates/molotov-bootstrap/src/sandbox.rs new file mode 100644 index 0000000..6e6913a --- /dev/null +++ b/crates/molotov-bootstrap/src/sandbox.rs @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +use crate::error::MolotovError; +use std::path::{Path, PathBuf}; +use std::process::Command; + +#[derive(Debug, Clone)] +pub struct SandboxConfig { + pub instance_id: String, + pub data_dir: PathBuf, + pub config_dir: PathBuf, + pub nice_priority: i32, +} + +pub struct SandboxRunner { + config: SandboxConfig, +} + +impl SandboxRunner { + pub fn new(config: SandboxConfig) -> Self { + Self { config } + } + + pub fn build_bwrap_args(&self, executable_path: &Path) -> Vec { + let mut args = vec![ + "--unshare-pid".to_string(), + "--unshare-ipc".to_string(), + "--ro-bind".to_string(), + "/usr".to_string(), + "/usr".to_string(), + "--ro-bind".to_string(), + "/lib".to_string(), + "/lib".to_string(), + "--ro-bind".to_string(), + "/lib64".to_string(), + "/lib64".to_string(), + "--dev".to_string(), + "/dev".to_string(), + "--proc".to_string(), + "/proc".to_string(), + "--tmpfs".to_string(), + "/tmp".to_string(), + ]; + + // Isolated XDG_DATA_HOME + args.push("--bind".to_string()); + args.push(self.config.data_dir.to_string_lossy().to_string()); + args.push(self.config.data_dir.to_string_lossy().to_string()); + + // Isolated XDG_CONFIG_HOME + args.push("--bind".to_string()); + args.push(self.config.config_dir.to_string_lossy().to_string()); + args.push(self.config.config_dir.to_string_lossy().to_string()); + + args.push("--".to_string()); + args.push(executable_path.to_string_lossy().to_string()); + + args + } + + pub fn check_bwrap_installed() -> Result<(), MolotovError> { + match Command::new("bwrap").arg("--version").output() { + Ok(output) if output.status.success() => Ok(()), + _ => Err(MolotovError::Sandbox( + "bubblewrap ('bwrap') is not installed. Please install it via your system package manager." + .to_string(), + )), + } + } +} diff --git a/crates/molotov-bootstrap/tests/sandbox_test.rs b/crates/molotov-bootstrap/tests/sandbox_test.rs new file mode 100644 index 0000000..3caedc7 --- /dev/null +++ b/crates/molotov-bootstrap/tests/sandbox_test.rs @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +use molotov_bootstrap::sandbox::{SandboxConfig, SandboxRunner}; +use std::path::PathBuf; + +#[test] +fn test_bwrap_arguments_contain_isolated_data_dir() { + let config = SandboxConfig { + instance_id: "test-acc-1".to_string(), + data_dir: PathBuf::from("/tmp/molotov_data"), + config_dir: PathBuf::from("/tmp/molotov_config"), + nice_priority: -5, + }; + + let runner = SandboxRunner::new(config); + let args = runner.build_bwrap_args(&PathBuf::from("/usr/bin/molotov")); + + assert!(args.contains(&"--unshare-pid".to_string())); + assert!(args.contains(&"--bind".to_string())); + assert!(args.iter().any(|a| a.contains("/tmp/molotov_data"))); +}