execsurface 0.1.0-alpha.2

Runtime execution-surface drift detection for Linux CI and developer workflows
use std::env;
use std::ffi::OsString;
use std::fs::{self, OpenOptions};
use std::io::Write;
use std::path::Path;
use std::process::ExitCode;

use execsurface_observe::{observe_command, CommandSpec};

const POLICY_PATH: &str = "execsurface-policy.json";
const WORKFLOW_PATH: &str = ".github/workflows/execsurface.yml";
const CHECKOUT_PIN: &str = "3d3c42e5aac5ba805825da76410c181273ba90b1";

pub fn run_doctor() -> ExitCode {
    println!("ExecSurface Doctor");
    println!();

    let mut ready = true;

    if env::consts::OS == "linux" {
        pass("Linux");
    } else {
        fail(
            &format!("unsupported OS: {}", env::consts::OS),
            "ExecSurface currently supports Linux only.",
        );
        ready = false;
    }

    if env::consts::ARCH == "x86_64" {
        pass("x86_64");
    } else {
        fail(
            &format!("unsupported architecture: {}", env::consts::ARCH),
            "ExecSurface currently supports x86_64 only.",
        );
        ready = false;
    }

    if env::consts::OS == "linux" && env::consts::ARCH == "x86_64" {
        match observe_command(&CommandSpec::new("/bin/true")) {
            Ok(observation)
                if observation.complete
                    && observation.outcome.exit_code == Some(0)
                    && observation.outcome.signal.is_none() =>
            {
                pass("ptrace observer available");
            }
            Ok(observation) => {
                fail(
                    "ptrace observer did not produce complete successful evidence",
                    &format!(
                        "exit_code={:?} signal={:?}; see docs/TROUBLESHOOTING.md#ptrace-restrictions",
                        observation.outcome.exit_code, observation.outcome.signal
                    ),
                );
                ready = false;
            }
            Err(error) => {
                fail(
                    "ptrace observer unavailable",
                    &format!("{error}; see docs/TROUBLESHOOTING.md#ptrace-restrictions"),
                );
                ready = false;
            }
        }
    } else {
        skip("ptrace observer check", "requires Linux x86_64");
    }

    match workspace_writable() {
        Ok(()) => pass("workspace writable"),
        Err(error) => {
            fail(
                "workspace is not writable",
                &format!("{error}; use a writable project directory for learn/init output"),
            );
            ready = false;
        }
    }

    pass(&format!("ExecSurface {}", env!("CARGO_PKG_VERSION")));

    println!();
    if ready {
        println!("Ready.");
        println!("Boundary: observed behavior is not all possible behavior.");
        ExitCode::SUCCESS
    } else {
        println!("Not ready.");
        println!("ExecSurface did not change privileges, sysctls, or security settings.");
        ExitCode::from(2)
    }
}

pub fn run_init(args: &[OsString]) -> Result<(), String> {
    let mut command: Option<String> = None;
    let mut github_actions = false;
    let mut force = false;
    let mut index = 0;

    while index < args.len() {
        match args[index].to_string_lossy().as_ref() {
            "--command" => {
                let value = args
                    .get(index + 1)
                    .ok_or_else(|| "init: --command requires a value".to_owned())?;
                let value = value.to_string_lossy().into_owned();
                if value.trim().is_empty() {
                    return Err("init: --command cannot be empty".to_owned());
                }
                if value.contains('\n') || value.contains('\r') {
                    return Err(
                        "init: --command must be a single-line shell command in public alpha"
                            .to_owned(),
                    );
                }
                command = Some(value);
                index += 2;
            }
            "--github-actions" => {
                github_actions = true;
                index += 1;
            }
            "--force" => {
                force = true;
                index += 1;
            }
            other => return Err(format!("init: unknown option: {other}")),
        }
    }

    let command = command.ok_or_else(|| {
        r#"init: missing --command. Example: execsurface init --command "cargo test --locked" --github-actions"#
            .to_owned()
    })?;

    let cwd = env::current_dir()
        .map_err(|error| format!("init: cannot read current directory: {error}"))?;
    let policy = cwd.join(POLICY_PATH);
    let workflow = cwd.join(WORKFLOW_PATH);

    let mut targets = vec![policy.clone()];
    if github_actions {
        targets.push(workflow.clone());
    }
    if !force {
        let existing = targets
            .iter()
            .filter(|path| path.exists())
            .map(|path| path.display().to_string())
            .collect::<Vec<_>>();
        if !existing.is_empty() {
            return Err(format!(
                "init: refusing to overwrite existing file(s): {}. Re-run with --force only after review.",
                existing.join(", ")
            ));
        }
    }

    write_file(
        &policy,
        "{\n  \"schema_version\": 2,\n  \"default_action\": \"review\",\n  \"rules\": []\n}\n",
        force,
    )?;

    if github_actions {
        let workflow_body = render_workflow(&command);
        write_file(&workflow, &workflow_body, force)?;
    }

    println!("ExecSurface init");
    println!("[CREATED] {}", policy.display());
    if github_actions {
        println!("[CREATED] {}", workflow.display());
    }
    println!("[NOT RUN] target command");
    println!();
    println!(
        "Next: learn the baseline explicitly using the same Bash wrapper as the GitHub Action:"
    );
    println!(
        "  execsurface learn -- /bin/bash -lc {}",
        shell_quote(&command)
    );
    println!();
    println!("Then check the same command:");
    println!(
        "  execsurface check --policy {} -- /bin/bash -lc {}",
        POLICY_PATH,
        shell_quote(&command)
    );
    println!();
    println!("Review generated files and the baseline before committing them.");
    Ok(())
}

fn render_workflow(command: &str) -> String {
    format!(
        "name: ExecSurface\n\non:\n  pull_request:\n  push:\n    branches: [main]\n\npermissions:\n  contents: read\n\njobs:\n  execsurface:\n    runs-on: ubuntu-24.04\n    steps:\n      - uses: actions/checkout@{CHECKOUT_PIN} # v7.0.1\n\n      - name: ExecSurface runtime drift\n        uses: AETHERXGLOBAL/execsurface@v0.1\n        with:\n          command: >-\n            {command}\n          baseline: execsurface.lock.json\n          policy: {POLICY_PATH}\n          fail-on-review: \"false\"\n"
    )
}

fn shell_quote(value: &str) -> String {
    format!("'{}'", value.replace('\'', "'\"'\"'"))
}

fn write_file(path: &Path, content: &str, force: bool) -> Result<(), String> {
    if let Some(parent) = path.parent() {
        fs::create_dir_all(parent)
            .map_err(|error| format!("init: cannot create {}: {error}", parent.display()))?;
    }

    let mut options = OpenOptions::new();
    options.write(true);
    if force {
        options.create(true).truncate(true);
    } else {
        options.create_new(true);
    }

    let mut file = options
        .open(path)
        .map_err(|error| format!("init: cannot write {}: {error}", path.display()))?;
    file.write_all(content.as_bytes())
        .map_err(|error| format!("init: cannot write {}: {error}", path.display()))
}

fn workspace_writable() -> Result<(), String> {
    let cwd = env::current_dir().map_err(|error| error.to_string())?;
    for attempt in 0..16_u32 {
        let probe = cwd.join(format!(
            ".execsurface-doctor-write-{}-{attempt}",
            std::process::id()
        ));
        match OpenOptions::new().write(true).create_new(true).open(&probe) {
            Ok(mut file) => {
                file.write_all(b"execsurface-doctor\n")
                    .map_err(|error| error.to_string())?;
                drop(file);
                fs::remove_file(&probe).map_err(|error| error.to_string())?;
                return Ok(());
            }
            Err(error) if error.kind() == std::io::ErrorKind::AlreadyExists => continue,
            Err(error) => return Err(error.to_string()),
        }
    }
    Err("could not allocate a unique write probe".to_owned())
}

fn pass(message: &str) {
    println!("[PASS] {message}");
}

fn fail(message: &str, action: &str) {
    println!("[FAIL] {message}");
    println!("       Action: {action}");
}

fn skip(message: &str, reason: &str) {
    println!("[SKIP] {message}: {reason}");
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn shell_quote_handles_single_quote_without_execution() {
        assert_eq!(shell_quote("echo 'x'"), "'echo '\"'\"'x'\"'\"''");
    }

    #[test]
    fn workflow_uses_stable_channel_and_reviewed_checkout_pin() {
        let workflow = render_workflow("cargo test --locked");
        assert!(workflow.contains("AETHERXGLOBAL/execsurface@v0.1"));
        assert!(workflow.contains(CHECKOUT_PIN));
        assert!(workflow.contains("command: >-\n            cargo test --locked"));
    }
}