vetto 0.2.21

Daemon-less sandbox + security layer for AI coding agents (Landlock/Seatbelt, TUI statusline, post-session audit reports)
Documentation
//! Tier detection, doctor output, force-tier override, dry-run.

use crate::common::*;

#[test]
fn doctor_reports_capabilities() {
    let out = doctor_output();
    assert!(out.contains("landlock:"), "doctor output: {out}");
    assert!(out.contains("unprivileged userns:"), "{out}");
    assert!(out.contains("chosen tier:"), "{out}");
}

#[test]
fn force_tier_override_selects_fs_only() {
    if detected_tier().as_deref() != Some("full") {
        eprintln!("SKIP: needs full tier to override from");
        return;
    }
    let proj = TempProject::new("forcetier");
    let out = run_vetto_env_in(proj.path(), &["doctor"], &[("VETTO_FORCE_TIER", "fs-only")]);
    let text = stdout(&out);
    assert!(
        text.lines()
            .any(|l| l.trim_start().starts_with("chosen tier:") && l.contains("fs-only")),
        "force fs-only did not apply: {text}"
    );
}

#[test]
fn dry_run_executes_nothing() {
    if !have_landlock() {
        eprintln!("SKIP: no tier");
        return;
    }
    let proj = TempProject::new("dryrun");
    let out = run_vetto_in(
        proj.path(),
        &["--dry-run", "--", "sh", "-c", "touch dry-ran-flag"],
    );
    let text = stdout(&out);
    assert!(text.contains("vetto dry-run"), "{text}");
    assert!(text.contains("tier:"), "{text}");
    // Nothing may have executed: only execution could create this file.
    assert!(
        !proj.path().join("dry-ran-flag").exists(),
        "dry-run executed the agent!"
    );
}

#[test]
fn fail_closed_without_landlock_is_reported() {
    // We cannot remove landlock at runtime; assert the honest-error path is
    // at least wired by checking the doctor wording once.
    let out = doctor_output();
    assert!(
        out.contains("landlock") && out.contains("tier"),
        "doctor must always discuss landlock/tier: {out}"
    );
}

#[test]
fn fs_only_with_denied_secrets_warns_about_degradation() {
    if detected_tier().as_deref() != Some("full") {
        eprintln!("SKIP: needs full tier to override from");
        return;
    }
    ensure_fake_ssh_key();
    let proj = TempProject::new("fsonly-warn");
    let out = run_vetto_env_in(
        proj.path(),
        &["--dry-run", "--", "sh", "-c", "true"],
        &[("VETTO_FORCE_TIER", "fs-only")],
    );
    let err = stderr(&out);
    assert!(
        err.contains("fs-only tier: display_only_deny paths"),
        "degradation warning must state the masking gap: {err}"
    );
    assert!(
        err.contains("cannot be read back"),
        "the write-root read-back cost must be stated: {err}"
    );
}