zerobox-linux-sandbox 0.3.3

Sandbox any command with file, network, and credential controls.
Documentation
#[cfg(debug_assertions)]
use std::fs::File;
#[cfg(debug_assertions)]
use std::io::BufRead;
use std::path::PathBuf;

#[cfg(debug_assertions)]
const BAZEL_BWRAP_ENV_VAR: &str = "CARGO_BIN_EXE_bwrap";

#[cfg(debug_assertions)]
pub(crate) fn candidate() -> Option<PathBuf> {
    if option_env!("BAZEL_PACKAGE").is_none() || !runfiles_env_present() {
        return None;
    }

    let raw = PathBuf::from(std::env::var_os(BAZEL_BWRAP_ENV_VAR)?);
    if raw.is_absolute() {
        return Some(raw);
    }
    resolve_runfile(raw.to_str()?)
}

#[cfg(not(debug_assertions))]
pub(crate) fn candidate() -> Option<PathBuf> {
    None
}

#[cfg(debug_assertions)]
fn runfiles_env_present() -> bool {
    std::env::var_os("RUNFILES_DIR").is_some()
        || std::env::var_os("TEST_SRCDIR").is_some()
        || std::env::var_os("RUNFILES_MANIFEST_FILE").is_some()
}

#[cfg(debug_assertions)]
fn resolve_runfile(logical_path: &str) -> Option<PathBuf> {
    let mut logical_paths = vec![logical_path.to_string()];
    if let Ok(workspace) = std::env::var("TEST_WORKSPACE")
        && !workspace.is_empty()
    {
        logical_paths.push(format!("{workspace}/{logical_path}"));
    }

    for root_env in ["RUNFILES_DIR", "TEST_SRCDIR"] {
        let Some(root) = std::env::var_os(root_env) else {
            continue;
        };
        let root = PathBuf::from(root);
        for logical_path in &logical_paths {
            let candidate = root.join(logical_path);
            if candidate.exists() {
                return Some(candidate);
            }
        }
    }

    let manifest = PathBuf::from(std::env::var_os("RUNFILES_MANIFEST_FILE")?);
    let file = File::open(manifest).ok()?;
    for line in std::io::BufReader::new(file).lines().map_while(Result::ok) {
        let Some((key, value)) = line.split_once(' ') else {
            continue;
        };
        if logical_paths.iter().any(|logical_path| logical_path == key) {
            return Some(PathBuf::from(value));
        }
    }
    None
}