a3s-box-runtime 3.1.0

MicroVM runtime engine — VM lifecycle, OCI images, attestation, networking
Documentation
use std::path::Path;

use a3s_runtime::contract::{RestartPolicy, RuntimeMount, RuntimeMountSource, RuntimeUnitState};
use a3s_runtime::RuntimeClient;

use super::fixture::BoxRuntimeConformanceFixture;
use super::{require, Result};

const TMPFS_SIZE_BYTES: u64 = 4 * 1024 * 1024;

pub(super) async fn run(
    fixture: &BoxRuntimeConformanceFixture,
    client: &dyn RuntimeClient,
) -> Result<()> {
    read_only_enforcement(fixture, client).await?;
    tmpfs_isolation(fixture, client).await?;
    mount_cleanup(fixture, client).await
}

async fn read_only_enforcement(
    fixture: &BoxRuntimeConformanceFixture,
    client: &dyn RuntimeClient,
) -> Result<()> {
    const TARGET: &str = "/mnt/r17-read-only";
    let mut request = fixture.cases.task(
        "mount-read-only",
        "if sh -c 'printf forbidden > /mnt/r17-read-only/forbidden' 2>/dev/null; then printf 'read-only tmpfs accepted a write\\n' >&2; exit 71; fi; test ! -e /mnt/r17-read-only/forbidden",
        10_000,
    );
    request.spec.mounts = vec![tmpfs("sealed", TARGET, true)];

    let observation = client.apply(&request).await?;
    require(
        observation.state == RuntimeUnitState::Succeeded,
        "read-only tmpfs accepted a workload write",
    )?;
    let record = fixture.record_for(&request.spec).await?;
    require_tmpfs_config(&record, TARGET, true)?;
    fixture
        .remove_unit(client, &request.spec, "mount-read-only")
        .await
}

async fn tmpfs_isolation(
    fixture: &BoxRuntimeConformanceFixture,
    client: &dyn RuntimeClient,
) -> Result<()> {
    const TARGET: &str = "/mnt/r17-isolation";
    let mut request = fixture.cases.task(
        "mount-tmpfs-isolation",
        "if [ ! -e /r17-tmpfs-restart-marker ]; then touch /r17-tmpfs-restart-marker; printf private > /mnt/r17-isolation/token; exit 17; fi; test ! -e /mnt/r17-isolation/token",
        10_000,
    );
    request.spec.mounts = vec![tmpfs("scratch", TARGET, false)];
    request.spec.restart = RestartPolicy::OnFailure { max_retries: 1 };
    let isolated = client.apply(&request).await?;
    require(
        isolated.state == RuntimeUnitState::Succeeded,
        "a restarted Runtime unit observed its prior tmpfs contents",
    )?;

    let record = fixture.record_for(&request.spec).await?;
    require(
        record
            .managed_execution
            .as_ref()
            .is_some_and(|metadata| metadata.generation.get() == 2),
        "tmpfs isolation fixture did not execute its required restart",
    )?;
    require_tmpfs_config(&record, TARGET, false)?;
    fixture
        .remove_unit(client, &request.spec, "mount-tmpfs-isolation")
        .await
}

async fn mount_cleanup(
    fixture: &BoxRuntimeConformanceFixture,
    client: &dyn RuntimeClient,
) -> Result<()> {
    const TARGET: &str = "/mnt/r17-cleanup";
    let mut service = fixture.cases.service(
        "mount-cleanup",
        "printf mounted > /mnt/r17-cleanup/marker; exec sleep 3600",
    );
    service.spec.mounts = vec![tmpfs("ephemeral", TARGET, false)];
    let running = client.apply(&service).await?;
    require(
        running.state == RuntimeUnitState::Running,
        "tmpfs cleanup fixture Service did not reach running",
    )?;

    let record = fixture.record_for(&service.spec).await?;
    require_live_tmpfs_mount(&record, TARGET, false)?;
    let pid = record
        .pid
        .ok_or_else(|| super::protocol("tmpfs cleanup fixture has no Sandbox init PID"))?;
    let mountinfo =
        std::fs::read_to_string(Path::new("/proc").join(pid.to_string()).join("mountinfo"))
            .map_err(|error| super::external("read tmpfs cleanup mount namespace", error))?;
    require(
        mountinfo
            .lines()
            .any(|line| line.contains(&format!(" {TARGET} ")) && line.contains(" - tmpfs ")),
        "running Sandbox did not expose the requested tmpfs mount",
    )?;
    let pid_start_time = record
        .pid_start_time
        .ok_or_else(|| super::protocol("tmpfs cleanup fixture has no init PID start time"))?;
    let box_dir = record.box_dir.clone();
    let (log_worker_pid, log_worker_pid_start_time) =
        require_log_worker_identity(fixture, &record)?;

    fixture
        .remove_unit(client, &service.spec, "mount-cleanup")
        .await?;
    require(
        !crate::process::is_process_alive_with_identity(pid, Some(pid_start_time)),
        "tmpfs owner process survived Runtime removal",
    )?;
    require(
        !crate::process::is_process_alive_with_identity(
            log_worker_pid,
            Some(log_worker_pid_start_time),
        ),
        "tmpfs log worker survived Runtime removal",
    )?;
    require(
        fixture
            .driver
            .find_generation(&service.spec)
            .await?
            .is_none(),
        "tmpfs cleanup left a provider execution record",
    )?;
    require(
        !box_dir.exists(),
        "tmpfs cleanup left its provider filesystem",
    )
}

fn require_log_worker_identity(
    fixture: &BoxRuntimeConformanceFixture,
    record: &crate::BoxRecord,
) -> Result<(u32, u64)> {
    let runtime = crate::vm::reap::load_recorded_sandbox_runtime(
        &fixture.home_dir,
        &record.box_dir,
        &record.id,
    )
    .map_err(|error| super::external("load tmpfs cleanup runtime", error))?
    .ok_or_else(|| super::protocol("tmpfs cleanup runtime record disappeared"))?;
    let pid = runtime
        .log_worker_pid
        .ok_or_else(|| super::protocol("tmpfs cleanup fixture has no log-worker PID"))?;
    let start_time = runtime
        .log_worker_pid_start_time
        .ok_or_else(|| super::protocol("tmpfs cleanup fixture has no log-worker start time"))?;
    Ok((pid, start_time))
}

fn tmpfs(name: &str, target: &str, read_only: bool) -> RuntimeMount {
    RuntimeMount {
        name: name.into(),
        source: RuntimeMountSource::Tmpfs {
            size_bytes: TMPFS_SIZE_BYTES,
        },
        target: target.into(),
        read_only,
    }
}

fn require_tmpfs_config(record: &crate::BoxRecord, target: &str, read_only: bool) -> Result<()> {
    let config = &record
        .managed_execution
        .as_ref()
        .ok_or_else(|| super::protocol("tmpfs fixture lost managed metadata"))?
        .request
        .config;
    let expected = format!(
        "{target}:size={TMPFS_SIZE_BYTES},{}",
        if read_only { "ro" } else { "rw" }
    );
    require(
        config.tmpfs == vec![expected],
        "Runtime tmpfs intent changed before provider launch",
    )
}

fn require_live_tmpfs_mount(
    record: &crate::BoxRecord,
    target: &str,
    read_only: bool,
) -> Result<()> {
    require_tmpfs_config(record, target, read_only)?;
    let bundle = record.box_dir.join("sandbox/bundle/config.json");
    let value: serde_json::Value = serde_json::from_slice(
        &std::fs::read(&bundle)
            .map_err(|error| super::external("read tmpfs Sandbox OCI configuration", error))?,
    )
    .map_err(|error| super::external("decode tmpfs Sandbox OCI configuration", error))?;
    let mount = value["mounts"]
        .as_array()
        .and_then(|mounts| {
            mounts
                .iter()
                .find(|mount| mount["destination"].as_str() == Some(target))
        })
        .ok_or_else(|| super::protocol("Sandbox OCI configuration omitted the Runtime tmpfs"))?;
    let options = mount["options"]
        .as_array()
        .ok_or_else(|| super::protocol("Runtime tmpfs has no OCI mount options"))?;
    let expected_mode = if read_only { "ro" } else { "rw" };
    let expected_size = format!("size={TMPFS_SIZE_BYTES}");
    require(
        mount["type"] == "tmpfs"
            && options.iter().any(|option| option == expected_mode)
            && options
                .iter()
                .any(|option| option.as_str() == Some(expected_size.as_str())),
        "Sandbox OCI tmpfs did not preserve size and access mode",
    )
}