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
//! Bubblewrap interface
//!
//! This module sets up the empty chroots with required mounts and initiates extraction within the
//! sandbox. In addition, the `LD_LIBRARY_PATH` is setup for GNU tar to start. The following are
//! mounted:
//! 1. GNU tar
//! 2. /lib64 (with an alternate name)
//! 3. The archive to extract

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

pub(super) struct BWParams<'a> {
    pub(super) chroot: ChrootVerified,
    pub(super) archive: &'a Path,
}

impl<'a> BWParams<'a> {
    pub(super) fn dispatch(&self, globals: &GlobalsFinal) -> AResult<()> {
        let archive = self.archive.canonicalize()?;
        let command = format!("tar {} --file={}", TARARGS.join(" "), archive.display());
        let args = HasNeither::new()
            .namespace(&NSCONF)
            .capabilities(&CAPABS)
            .usercfg(&USRCONF)
            .chroot(Path::new("/"))
            .chdir(&self.chroot)
            .command(&command)
            .build();
        launch(args, globals)?;
        Ok(())
    }
}

// Some sources suggest the excludes must come before source and target
const TARARGS: &[&str] = &[
    "--exclude=dev/*",
    "--exclude=proc/*",
    "--extract",
    "--verbose",
    "--preserve-permissions",
    "--xattrs-include='*.*'",
    "--numeric-owner",
];

const NSCONF: [&str; 2] = ["--unshare-all", "--unshare-user"];
const USRCONF: [&str; 4] = ["--uid", "0", "--gid", "0"];

/// Capabilities to add to superuser inside the chroot
///
/// Refer the following:
/// - `capablilites(7)`
/// - `user_namespaces(7)`
/// - `bwrap(1)`
///
/// The following capabilities are used:
/// - `CAP_CHOWN`: For changing file ownership
/// - `CAP_FOWNER`: For changing file permissions
/// - `CAP_SETFCAP`: Setcap on binaries
const CAPABS: [&str; 3] = ["CAP_CHOWN", "CAP_FOWNER", "CAP_SETFCAP"];