genpac 0.1.0

Sandbox for Gentoo ebuild development using bubblewrap
// Copyright (C) 2023 Gokul Das B
// SPDX-License-Identifier: GPL-3.0-or-later
//! Bubblwrap interface
//!
//! This module interfaces the sandbox configuration system with the bubblwrap module, with
//! appropriate vaules of capabilities, environment variables, etc.

use crate::bubblewrap::{launch, HasNeither};
use crate::global::ChrootVerified;
use crate::GlobalsFinal;
use anyhow::Result as AResult;
use std::path::PathBuf;

pub(super) struct BWParams {
    pub(super) chroot: ChrootVerified,
    pub(super) tmpfs_size: usize,
    pub(super) command: String,
    pub(super) mounts: Vec<(PathBuf, PathBuf)>,
}

impl BWParams {
    pub(super) fn dispatch(self, globals: &GlobalsFinal) -> AResult<()> {
        let tag = format!("{}", self.chroot);
        let mut args = HasNeither::new()
            .namespace(&NSCONF)
            .capabilities(&CAPABS)
            .usercfg(&USRCONF)
            .sysmounts(&SYSMOUNTS)
            .add_var("GENPAC", &tag)
            .tmpfs(self.tmpfs_size)
            .resolve()
            .chroot(&self.chroot)
            .command(&self.command);
        for (src, dest) in &self.mounts {
            args = args.add_mount(src, dest);
        }
        let args = args.build();

        launch(args, globals)?;
        Ok(())
    }
}

const NSCONF: [&str; 3] = ["--unshare-all", "--unshare-user", "--share-net"];
const USRCONF: [&str; 4] = ["--uid", "0", "--gid", "0"];
const SYSMOUNTS: [&str; 8] = [
    "--dev", "/dev", "--proc", "/proc", "--perms", "1777", "--tmpfs", "/dev/shm",
];

/// Capabilities to add to superuser inside the chroot
///
/// Refer the following:
/// - `capablilites(7)`
/// - `user_namespaces(7)`
/// - `bwrap(1)`
///
/// The following capabilities are used:
/// - `CAP_SYS_ADMIN`: For nested user namespace for build sandbox. REVIEW: Very broad permissions
/// - `CAP_NET_ADMIN`: Used to configure loopback interface
/// - `CAP_CHOWN`: Needed by portage to change ownership of repos
/// - `CAP_FOWNER`: Needed by portage to change permissions on log file
/// - `CAP_DAC_OVERRIDE`: Used by portage for accessing log file, etc (UID: 250/portage)
/// - `CAP_SETUID`: Used by portage
/// - `CAP_SETGID`: Used by portage
/// - `CAP_SETFCAP`: Needed by portage to setcap on installed packages
const CAPABS: [&str; 8] = [
    "CAP_SYS_ADMIN",
    "CAP_NET_ADMIN",
    "CAP_CHOWN",
    "CAP_FOWNER",
    "CAP_DAC_OVERRIDE",
    "CAP_SETUID",
    "CAP_SETGID",
    "CAP_SETFCAP",
];