cellos-supervisor 0.5.1

CellOS execution-cell runner — boots cells in Firecracker microVMs or gVisor, enforces narrow typed authority, emits signed CloudEvents.
Documentation
//! Linux-only: P0-3 / I3 — `spec.run.limits.cpuMax` flows to the cgroup CPU
//! controller (`cpu.max`) for the host-subprocess backend.
//!
//! Uses [`cellos_supervisor::linux_cgroup::apply_cpu_max_to_leaf`] against a
//! tempdir simulating a cgroup v2 leaf so the file-write path is exercised
//! without a real cgroup hierarchy (real cgroup integration is the `--ignored`
//! test under `supervisor_linux_unshare.rs`).
//!
//! Doctrine D1: env override (`CELLOS_CGROUP_CPU_MAX`) is *not* a default — it
//! only applies when the spec is silent. The negative test below proves that
//! when both are absent, **nothing** is written, so the kernel's own `max`
//! default stays in effect.

#![cfg(target_os = "linux")]

use std::fs;

use cellos_core::types::{RunCpuMax, RunLimits};
use cellos_supervisor::linux_cgroup::{apply_cpu_max_to_leaf, CpuMaxApplyOutcome, CpuMaxSource};

fn limits_with_cpu(quota: u64, period: Option<u64>) -> RunLimits {
    RunLimits {
        memory_max_bytes: None,
        cpu_max: Some(RunCpuMax {
            quota_micros: quota,
            period_micros: period,
        }),
        graceful_shutdown_seconds: None,
    }
}

/// Positive: when `spec.run.limits.cpuMax` is present, the supervisor writes
/// the cgroup v2 `cpu.max` payload to the leaf. The schema field is the
/// **primary** source — even if `CELLOS_CGROUP_CPU_MAX` is set to a different
/// value, the spec wins (D1 — env is an override, not a default override).
#[test]
fn cpu_max_from_spec_is_written_to_leaf() {
    let dir = tempfile::tempdir().expect("tempdir");
    let leaf = dir.path();

    let limits = limits_with_cpu(50_000, Some(100_000));
    let outcome = apply_cpu_max_to_leaf(
        leaf,
        Some(&limits),
        Some("max 200000"), // env override that should be ignored when spec is set
    );

    match outcome {
        CpuMaxApplyOutcome::Wrote { source, payload } => {
            assert_eq!(source, CpuMaxSource::Spec, "spec must be primary source");
            assert_eq!(payload, "50000 100000");
        }
        other => panic!("expected Wrote{{Spec,...}}, got {other:?}"),
    }

    let written = fs::read_to_string(leaf.join("cpu.max")).expect("read cpu.max");
    assert_eq!(
        written, "50000 100000\n",
        "cpu.max payload must match spec quota/period (kernel parses without trailing newline; we add one for readability)"
    );
}

/// Negative: when `spec.run.limits.cpuMax` is **absent** AND
/// `CELLOS_CGROUP_CPU_MAX` is unset, the supervisor must NOT write a `cpu.max`
/// file. Skipping the write leaves the kernel default (`max 100000`,
/// effectively unlimited) — i.e. the limit is genuinely **removed**, not
/// silently substituted with a fallback.
///
/// This is the key D1 invariant: removing the spec field actually removes the
/// limit, not just defers to a hidden ambient default.
#[test]
fn cpu_max_not_written_when_spec_silent_and_env_unset() {
    let dir = tempfile::tempdir().expect("tempdir");
    let leaf = dir.path();
    let cpu_max_path = leaf.join("cpu.max");

    // Sanity: file must not exist before the call.
    assert!(!cpu_max_path.exists(), "tempdir starts clean");

    // Spec absent (limits=None), env absent (None).
    let outcome = apply_cpu_max_to_leaf(leaf, None, None);
    assert_eq!(outcome, CpuMaxApplyOutcome::Skipped);

    assert!(
        !cpu_max_path.exists(),
        "no cpu.max must be written when neither spec nor env supplied a value (kernel default remains in effect)"
    );

    // Same outcome when limits is `Some(RunLimits)` but `cpu_max` is None.
    let limits_no_cpu = RunLimits {
        memory_max_bytes: None,
        cpu_max: None,
        graceful_shutdown_seconds: None,
    };
    let outcome = apply_cpu_max_to_leaf(leaf, Some(&limits_no_cpu), None);
    assert_eq!(outcome, CpuMaxApplyOutcome::Skipped);
    assert!(
        !cpu_max_path.exists(),
        "limits.cpuMax=None must behave identically to limits=None"
    );

    // Same outcome when env is set but empty.
    let outcome = apply_cpu_max_to_leaf(leaf, None, Some(""));
    assert_eq!(outcome, CpuMaxApplyOutcome::Skipped);
    assert!(
        !cpu_max_path.exists(),
        "empty CELLOS_CGROUP_CPU_MAX is not a default; no write"
    );
}

/// Override path: spec silent, env explicitly set → env value is normalized
/// and written. Confirms the env knob still works as documented for operators
/// who haven't migrated to the typed schema field.
#[test]
fn cpu_max_env_override_used_when_spec_silent() {
    let dir = tempfile::tempdir().expect("tempdir");
    let leaf = dir.path();

    let outcome = apply_cpu_max_to_leaf(leaf, None, Some("25000 100000"));
    match outcome {
        CpuMaxApplyOutcome::Wrote { source, payload } => {
            assert_eq!(source, CpuMaxSource::EnvOverride);
            assert_eq!(payload, "25000 100000");
        }
        other => panic!("expected Wrote{{EnvOverride,...}}, got {other:?}"),
    }

    let written = fs::read_to_string(leaf.join("cpu.max")).expect("read cpu.max");
    assert_eq!(written, "25000 100000\n");
}

/// Malformed env override + silent spec: no file is written and the outcome
/// surfaces the diagnostic so the supervisor can warn.
#[test]
fn cpu_max_invalid_env_override_does_not_write() {
    let dir = tempfile::tempdir().expect("tempdir");
    let leaf = dir.path();

    let outcome = apply_cpu_max_to_leaf(leaf, None, Some("not-a-number"));
    assert_eq!(outcome, CpuMaxApplyOutcome::InvalidEnvOverride);
    assert!(!leaf.join("cpu.max").exists());
}