vvbox 0.1.0

Lightweight sandbox runner for macOS 26 using Apple container CLI.
Documentation
//! Core data types for configuration and run metadata.

use serde::{Deserialize, Serialize};
use std::collections::HashMap;

/// Command list representation used by config files.
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(untagged)]
pub enum CommandList {
    /// Single command string.
    One(String),
    /// Multiple command strings.
    Many(Vec<String>),
}

impl CommandList {
    /// Normalize the command list into a vector of strings.
    pub fn to_vec(&self) -> Vec<String> {
        match self {
            CommandList::One(s) => vec![s.clone()],
            CommandList::Many(v) => v.clone(),
        }
    }
}

/// Volume specification as provided in configuration.
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(untagged)]
pub enum VolumeSpec {
    /// String form `source:target[:ro]` or `vvbox:<name>:<target>[:ro]`.
    String(String),
    /// Object form with explicit fields.
    Object {
        /// Volume source path or `vvbox:<name>`.
        source: String,
        /// Container mount target.
        target: String,
        /// Read-only mount flag.
        #[serde(default)]
        readonly: bool,
    },
}

/// Fully resolved volume mount.
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct VolumeMount {
    /// Host path for the mount.
    pub source: String,
    /// Container target path.
    pub target: String,
    /// Whether the mount is read-only.
    pub readonly: bool,
}

/// Service container configuration from config files.
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
pub struct ServiceConfig {
    /// Service name used in container naming.
    pub name: String,
    /// Container image name.
    pub image: String,
    /// Environment variables for the service.
    #[serde(default)]
    pub env: Option<HashMap<String, String>>,
    /// Port mappings (host:container[/proto]).
    #[serde(default)]
    pub ports: Option<Vec<String>>,
    /// Volume mounts for the service.
    #[serde(default)]
    pub volumes: Option<Vec<VolumeSpec>>,
    /// Optional command override.
    #[serde(default)]
    pub command: Option<CommandList>,
    /// Optional working directory inside the container.
    #[serde(default)]
    pub workdir: Option<String>,
}

/// Raw configuration file as read from YAML/JSON.
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
pub struct ConfigFile {
    /// Base image for the main run container.
    #[serde(default)]
    pub image: Option<String>,
    /// Network name.
    #[serde(default)]
    pub network: Option<String>,
    /// Working directory inside the container.
    #[serde(default)]
    pub workdir: Option<String>,
    /// Environment variables for the main run.
    #[serde(default)]
    pub env: Option<HashMap<String, String>>,
    /// Volume specifications.
    #[serde(default)]
    pub volumes: Option<Vec<VolumeSpec>>,
    /// Port mappings (host:container[/proto]).
    #[serde(default)]
    pub ports: Option<Vec<String>>,
    /// Commands to run before the main command.
    #[serde(default)]
    pub pre_install: Option<CommandList>,
    /// Commands to run for the task.
    #[serde(default)]
    pub run: Option<CommandList>,
    /// Service container configs.
    #[serde(default)]
    pub services: Option<Vec<ServiceConfig>>,
}

/// Fully resolved configuration with defaults applied.
#[derive(Debug, Clone)]
pub struct ResolvedConfig {
    /// Container image name.
    pub image: String,
    /// Optional network name.
    pub network: Option<String>,
    /// Working directory inside the container.
    pub workdir: String,
    /// Environment variables.
    pub env: HashMap<String, String>,
    /// Resolved volume mounts.
    pub volumes: Vec<VolumeMount>,
    /// Port mappings.
    pub ports: Vec<String>,
    /// Pre-install command list.
    pub pre_install: Vec<String>,
    /// Main run command list.
    pub run: Vec<String>,
    /// Service configurations.
    pub services: Vec<ServiceConfig>,
}

/// Metadata describing a single vvbox run.
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct RunMeta {
    /// Unique run id.
    pub id: String,
    /// Timestamp (RFC 3339).
    pub created_at: String,
    /// Absolute path to the repo root.
    pub repo_root: String,
    /// Path to the snapshot/worktree.
    pub snapshot_path: String,
    /// Snapshot mode ("worktree" or "in-place").
    pub snapshot_mode: String,
    /// Main container name.
    pub container_name: String,
    /// Image used for the main container.
    pub image: String,
    /// Working directory inside the container.
    pub workdir: String,
    /// Network name, if any.
    #[serde(default)]
    pub network: Option<String>,
    /// Environment variables applied to the run.
    #[serde(default)]
    pub env: HashMap<String, String>,
    /// Volume mounts applied to the run.
    #[serde(default)]
    pub volumes: Vec<VolumeMount>,
    /// Published ports.
    #[serde(default)]
    pub ports: Vec<String>,
    /// Command executed in the container.
    pub command: Vec<String>,
    /// Pre-install commands.
    #[serde(default)]
    pub pre_install: Vec<String>,
    /// Run commands from config.
    #[serde(default)]
    pub run: Vec<String>,
    /// Service container names started for the run.
    #[serde(default)]
    pub services: Vec<String>,
    /// Whether the run used in-place mode.
    #[serde(default)]
    pub in_place: bool,
    /// Optional task label.
    #[serde(default)]
    pub task: Option<String>,
    /// Exit code from the container process.
    #[serde(default)]
    pub exit_code: Option<i32>,
    /// Status string (created/ran/failed).
    pub status: String,
}