shepherd-cli 6.6.1

The canonical shepherd command-line interface over the per-project registry, run artifacts, and sprint pipeline.
mod support;

use serde_json::{Value, json};
use sha2::{Digest, Sha256};
use std::{
    fs,
    io::Write,
    path::{Path, PathBuf},
    process::{Command, Output, Stdio},
};

struct Fixture(PathBuf);
impl Drop for Fixture {
    fn drop(&mut self) {
        support::remove_dir_all(&self.0);
    }
}

fn fixture() -> Fixture {
    let root = fs::canonicalize(std::env::temp_dir())
        .unwrap()
        .join(format!("shepherd-transport-bind-{}", uuid::Uuid::now_v7()));
    fs::create_dir(&root).unwrap();
    assert!(
        Command::new("git")
            .args(["init", "--quiet"])
            .current_dir(&root)
            .status()
            .unwrap()
            .success()
    );
    Fixture(root)
}

fn invoke(root: &Path, args: &[&str], input: Option<Value>) -> Output {
    let mut command = Command::new(env!("CARGO_BIN_EXE_shepherd"));
    command
        .args(args)
        .current_dir(root)
        .env("SHEPHERD_HOME", root.join("isolated-home"))
        .env_remove("SHEPHERD_NATIVE_DESCRIPTOR")
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .stderr(Stdio::piped());
    let mut child = command.spawn().unwrap();
    if let Some(input) = input {
        child
            .stdin
            .take()
            .unwrap()
            .write_all(&serde_json::to_vec(&input).unwrap())
            .unwrap();
    }
    drop(child.stdin.take());
    child.wait_with_output().unwrap()
}

fn install(root: &Path, target: &str) -> PathBuf {
    let installed = root.join(format!("installed-{target}"));
    let result = invoke(
        root,
        &[
            "compile",
            "--target",
            target,
            "--out",
            installed.to_str().unwrap(),
        ],
        None,
    );
    assert!(
        result.status.success(),
        "{}",
        String::from_utf8_lossy(&result.stderr)
    );
    installed
}

fn request(installed: &Path, harness: &str) -> Value {
    json!({"schema":"shepherd.native-transport-bind/1", "harness":harness,
        "installed_package_root":installed})
}

#[test]
fn ordinary_installed_carriers_receive_native_selected_protected_transport() {
    for (target, harness) in [("claude", "claude-code"), ("codex", "codex"), ("pi", "pi")] {
        let fixture = fixture();
        let root = &fixture.0;
        let installed = install(root, target);
        let result = invoke(
            root,
            &["dispatch", "transport-bind"],
            Some(request(&installed, harness)),
        );
        assert!(
            result.status.success(),
            "{harness}: {}",
            String::from_utf8_lossy(&result.stderr)
        );
        let binding: Value = serde_json::from_slice(&result.stdout).unwrap();
        assert_eq!(binding["schema"], "shepherd.native-transport-binding/1");
        let path = PathBuf::from(binding["descriptor_path"].as_str().unwrap());
        assert!(path.starts_with(root.join(".shepherd/tmp/native-transports")));
        let descriptor: Value = serde_json::from_slice(&fs::read(&path).unwrap()).unwrap();
        assert_eq!(descriptor["schema"], "shepherd.native-transport/2");
        assert_eq!(descriptor["project_root"], root.to_str().unwrap());
        assert_eq!(
            descriptor["installed_package_root"],
            installed.to_str().unwrap()
        );
        let binary = fs::canonicalize(env!("CARGO_BIN_EXE_shepherd")).unwrap();
        assert_eq!(descriptor["binary"], binary.to_str().unwrap());
        assert_eq!(
            descriptor["candidate_sha256"],
            Sha256::digest(fs::read(binary).unwrap())
                .iter()
                .map(|byte| format!("{byte:02x}"))
                .collect::<String>()
        );
        assert_eq!(descriptor["env"], json!({}));
        assert!(descriptor.get("auth_snapshot").is_none());
        assert!(
            !root.join(".shepherd/runs").exists(),
            "package binding creates no run or dispatch authority"
        );
        #[cfg(unix)]
        {
            use std::os::unix::fs::{MetadataExt, PermissionsExt};
            let metadata = fs::metadata(&path).unwrap();
            assert_eq!(metadata.nlink(), 1);
            assert_eq!(metadata.permissions().mode() & 0o777, 0o600);
            assert_eq!(
                fs::metadata(path.parent().unwrap())
                    .unwrap()
                    .permissions()
                    .mode()
                    & 0o777,
                0o700
            );
        }
    }
}

#[test]
fn transport_binding_rejects_caller_authority_fields_and_mismatched_carriers() {
    let fixture = fixture();
    let root = &fixture.0;
    let installed = install(root, "pi");
    for field in [
        "binary",
        "project_root",
        "session_id",
        "role",
        "env",
        "auth_snapshot",
        "candidate_sha256",
        "destination",
    ] {
        let mut input = request(&installed, "pi");
        input[field] = json!("caller-choice");
        let result = invoke(root, &["dispatch", "transport-bind"], Some(input));
        assert!(!result.status.success(), "accepted {field}");
        assert!(!root.join(".shepherd/tmp/native-transports").exists());
    }
    let wrong = invoke(
        root,
        &["dispatch", "transport-bind"],
        Some(request(&installed, "codex")),
    );
    assert!(!wrong.status.success());
    assert!(!root.join(".shepherd/tmp/native-transports").exists());
    fs::write(
        installed.join("skills/start/SKILL.md"),
        b"unverified startup override\n",
    )
    .unwrap();
    let changed = invoke(
        root,
        &["dispatch", "transport-bind"],
        Some(request(&installed, "pi")),
    );
    assert!(!changed.status.success());
    assert!(!root.join(".shepherd/tmp/native-transports").exists());
}

#[cfg(unix)]
#[test]
fn transport_binding_refuses_installed_and_destination_symlinks() {
    let fixture = fixture();
    let root = &fixture.0;
    let installed = install(root, "pi");
    let alias = root.join("installed-alias");
    std::os::unix::fs::symlink(&installed, &alias).unwrap();
    let result = invoke(
        root,
        &["dispatch", "transport-bind"],
        Some(request(&alias, "pi")),
    );
    assert!(!result.status.success());
    let outside = root.join("outside");
    fs::create_dir(&outside).unwrap();
    fs::create_dir_all(root.join(".shepherd")).unwrap();
    std::os::unix::fs::symlink(&outside, root.join(".shepherd/tmp")).unwrap();
    let result = invoke(
        root,
        &["dispatch", "transport-bind"],
        Some(request(&installed, "pi")),
    );
    assert!(!result.status.success());
    assert_eq!(fs::read_dir(outside).unwrap().count(), 0);
}