supercode-harness 0.4.21

The optional native Supercode agent and tool harness
Documentation
//! ONT-4: the four orchestration verbs, driven through the RPC the way a client does.
//!
//! Every assertion here goes through `HarnessSessionService::handle` —
//! `harness.v1.orchestration.compile|decompile|load|save` — so what is measured is the
//! door, not the codec beneath it. The codec is used only to prepare a fixture
//! (the fixture home's secret VALUES, which the wire is never allowed to
//! carry, have to come from somewhere the wire is not).

use std::collections::BTreeMap;
use std::fs;
use std::path::{Path, PathBuf};

use serde_json::{json, Value};
use supercode_harness::harness_service::HARNESS_SERVICE_METHODS;
use supercode_harness::{HarnessSessionService, SdkOperation};

fn fixture() -> PathBuf {
    PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("tests/fixtures/hermes_home")
        .canonicalize()
        .unwrap()
}

fn scratch(tag: &str) -> PathBuf {
    let root = std::env::temp_dir().join(format!(
        "supercode-ont4-{tag}-{}-{}",
        std::process::id(),
        std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap()
            .as_nanos()
    ));
    fs::create_dir_all(&root).unwrap();
    root.canonicalize().unwrap()
}

fn call(service: &mut HarnessSessionService, method: &str, params: Value) -> Value {
    let response = service.handle(json!({
        "jsonrpc": "2.0", "id": 1, "method": method, "params": params
    }));
    assert!(response.get("error").is_none(), "{method}: {response}");
    response["result"].clone()
}

fn files_under(root: &Path) -> BTreeMap<String, Vec<u8>> {
    fn walk(base: &Path, dir: &Path, out: &mut BTreeMap<String, Vec<u8>>) {
        for entry in fs::read_dir(dir).unwrap().flatten() {
            let path = entry.path();
            if path.is_dir() {
                walk(base, &path, out);
            } else if path.is_file() {
                out.insert(
                    path.strip_prefix(base)
                        .unwrap()
                        .to_string_lossy()
                        .into_owned(),
                    fs::read(&path).unwrap(),
                );
            }
        }
    }
    let mut out = BTreeMap::new();
    walk(root, root, &mut out);
    out
}

/// The fixture's secret values, read the only way that is allowed to read
/// them: off the disk, through the codec, in this process.
fn fixture_vault() -> BTreeMap<String, String> {
    supercode_harness::orchestration::codec::from_hermes(&fixture())
        .unwrap()
        .vault
}

#[test]
fn the_world_methods_are_published_and_have_operations() {
    for method in [
        "harness.v1.orchestration.load",
        "harness.v1.orchestration.save",
        "harness.v1.orchestration.compile",
        "harness.v1.orchestration.decompile",
        "harness.v1.orchestration.import",
        "harness.v1.orchestration.export",
    ] {
        assert!(
            HARNESS_SERVICE_METHODS.contains(&method),
            "`{method}` is not published"
        );
        assert!(
            SdkOperation::from_method(method).is_some(),
            "`{method}` has no SDK operation"
        );
    }
    for action in [
        "orchestration_load",
        "orchestration_save",
        "orchestration_compile",
        "orchestration_decompile",
        "orchestration_import",
        "orchestration_export",
        "workflow_load",
    ] {
        assert!(
            SdkOperation::from_action_name(action).is_some(),
            "`{action}` is not a stable action spelling"
        );
    }
}

#[test]
fn compile_from_hermes_answers_the_world_and_the_vault_key_names_only() {
    let mut service = HarnessSessionService::new();
    let result = call(
        &mut service,
        "harness.v1.orchestration.compile",
        json!({"from": "hermes", "home": fixture()}),
    );

    let names: Vec<&str> = result["orchestration"]["profiles"]
        .as_object()
        .expect("the orchestration carries its profiles")
        .keys()
        .map(String::as_str)
        .collect();
    assert_eq!(names, vec!["coder", "default", "ops"]);

    let keys: Vec<&str> = result["vault_keys"]
        .as_array()
        .unwrap()
        .iter()
        .map(|k| k.as_str().unwrap())
        .collect();
    assert!(
        keys.contains(&"TELEGRAM_TOKEN"),
        "the vault's key names come back: {keys:?}"
    );

    // No credential VALUE crosses the wire — not the whole answer, vault key
    // names included.
    let wire = serde_json::to_string(&result).unwrap();
    assert!(
        !wire.contains("FAKE-TOKEN-DO-NOT-EMIT"),
        "the fixture's telegram token was emitted"
    );
    let vault = fixture_vault();
    assert!(!vault.is_empty(), "the fixture has secrets to keep");
    for (key, value) in &vault {
        assert!(
            !wire.contains(value.as_str()),
            "`{key}`'s value crossed the wire"
        );
    }
}

#[test]
fn decompile_to_hermes_of_an_unchanged_world_reuses_the_store_and_refuses_nothing() {
    let mut service = HarnessSessionService::new();
    let compiled = call(
        &mut service,
        "harness.v1.orchestration.compile",
        json!({"from": "hermes", "home": fixture()}),
    );
    let dest = scratch("hermes-back");
    let report = call(
        &mut service,
        "harness.v1.orchestration.decompile",
        json!({
            "to": "hermes",
            "orchestration": compiled["orchestration"],
            "source": fixture(),
            "dest": dest,
        }),
    );

    assert_eq!(
        report["refused"].as_array().unwrap(),
        &Vec::<Value>::new(),
        "nothing changed, so nothing is refused"
    );
    let byte: Vec<&str> = report["written"]
        .as_array()
        .unwrap()
        .iter()
        .filter(|a| a["fidelity"] == "byte_lossless")
        .map(|a| a["path"].as_str().unwrap())
        .collect();
    assert!(
        byte.iter().any(|path| path.ends_with("state.db")),
        "an unchanged state.db is reused byte for byte: {byte:?}"
    );
    for path in &byte {
        assert_eq!(
            fs::read(dest.join(path)).unwrap(),
            fs::read(fixture().join(path)).unwrap(),
            "{path} byte for byte"
        );
    }
}

#[test]
fn load_and_save_round_trip_our_folder_byte_for_byte() {
    let mut service = HarnessSessionService::new();
    // A home to round-trip: the fixture compiled into our own folder, with the
    // secrets supplied through `save`'s own `vault` parameter.
    let compiled = call(
        &mut service,
        "harness.v1.orchestration.compile",
        json!({"from": "hermes", "home": fixture()}),
    );
    let root = scratch("our-folder");
    let saved = call(
        &mut service,
        "harness.v1.orchestration.save",
        json!({"root": root, "orchestration": compiled["orchestration"], "vault": fixture_vault()}),
    );
    assert_eq!(saved["written"], json!(true));
    assert_eq!(saved["root"], json!(root));

    let before = files_under(&root);
    assert!(
        before.contains_key("config.yaml") && before.contains_key(".env"),
        "the home was written: {:?}",
        before.keys().collect::<Vec<_>>()
    );
    assert!(
        String::from_utf8_lossy(&before[".env"]).contains("TELEGRAM_TOKEN="),
        "secrets land in .env, never in the orchestration"
    );

    let read = call(
        &mut service,
        "harness.v1.orchestration.load",
        json!({"root": root}),
    );
    assert_eq!(
        read["orchestration"]["root"],
        json!(root),
        "the orchestration names the folder it was read from"
    );
    let keys: Vec<&str> = read["vault_keys"]
        .as_array()
        .unwrap()
        .iter()
        .map(|k| k.as_str().unwrap())
        .collect();
    assert!(keys.contains(&"TELEGRAM_TOKEN"), "{keys:?}");
    let wire = serde_json::to_string(&read).unwrap();
    for (key, value) in fixture_vault() {
        assert!(
            !wire.contains(value.as_str()),
            "`{key}`'s value was read out"
        );
    }

    // Save what was loaded, with no vault: the home keeps its own secrets and
    // every artifact keeps its bytes.
    call(
        &mut service,
        "harness.v1.orchestration.save",
        json!({"root": root, "orchestration": read["orchestration"]}),
    );
    let after = files_under(&root);
    assert_eq!(
        after.keys().collect::<Vec<_>>(),
        before.keys().collect::<Vec<_>>(),
        "save(load(root)) writes the same files"
    );
    assert!(
        after == before,
        "save(load(root)) == root byte for byte; first difference: {:?}",
        before
            .iter()
            .find(|(name, bytes)| after.get(*name) != Some(*bytes))
            .map(|(name, _)| name)
    );
}

/// ONT-7: a migration in and back out through the RPC, with no secret VALUE
/// in any request or answer. The import lands the fixture's credential in our
/// `.env` and a ref in our `config.yaml`; the export puts the value back where
/// Hermes reads it and refuses the session half.
#[test]
fn import_then_export_move_the_credential_without_it_crossing_the_wire() {
    let mut service = HarnessSessionService::new();
    let vault = fixture_vault();
    let token = vault["TELEGRAM_TOKEN"].clone();
    let into = scratch("import-into");
    let imported = call(
        &mut service,
        "harness.v1.orchestration.import",
        json!({"from": "hermes", "home": fixture(), "into": into}),
    );
    assert!(
        !imported.to_string().contains(&token),
        "the answer carries no secret value"
    );
    assert!(imported["vault_keys"]
        .as_array()
        .unwrap()
        .iter()
        .any(|k| k == "TELEGRAM_TOKEN"));
    assert_eq!(imported["root"], json!(into));
    let env = fs::read_to_string(into.join(".env")).unwrap();
    assert!(env.contains(&token), ".env holds the value");
    let config = fs::read_to_string(into.join("config.yaml")).unwrap();
    assert!(
        config.contains("dotenv") && !config.contains(&token),
        "config.yaml holds a ref, never the value: {config}"
    );
    let carried: Vec<&str> = imported["carried"]
        .as_array()
        .unwrap()
        .iter()
        .map(|c| c.as_str().unwrap())
        .collect();
    for rel in &carried {
        assert_eq!(
            fs::read(into.join(rel)).unwrap(),
            fs::read(fixture().join(rel)).unwrap(),
            "{rel} carried byte for byte"
        );
    }

    let dest = scratch("export-dest");
    let report = call(
        &mut service,
        "harness.v1.orchestration.export",
        json!({"to": "hermes", "root": into, "dest": dest}),
    );
    let out = fs::read_to_string(dest.join("config.yaml")).unwrap();
    assert!(
        out.contains(&token) && !out.contains("dotenv"),
        "Hermes reads the value from config.yaml: {out}"
    );
    assert!(
        report["refused"]
            .as_array()
            .unwrap()
            .iter()
            .any(|r| r["file"] == "state.db" && r["reason"].as_str().unwrap().contains("UNI-22")),
        "our state.db is never written as Hermes's: {}",
        report["refused"]
    );
}