haematite-cli 0.21.7

The haematite command: serve a store, its door and Studio, answer MCP, query with jq, and host the store's assistant seat
Documentation
#![forbid(unsafe_code)]

use std::error::Error;

use haematite_cli::serve::contracts::{Contract, MutationRequest, Receipt, ResolvedMutation};
use haematite_cli::serve::protocol::Version;
use serde_json::{Value, json};

type TestResult = Result<(), Box<dyn Error>>;

const fn version(sequence: u64) -> Version {
    Version {
        generation: 7,
        sequence,
    }
}

fn request_value() -> Value {
    json!({
        "request_id": "write-1", "branch": "main",
        "caller": {"issuer": "local", "subject": "1001"},
        "contract": {"kind": "exact_version", "expected": version(2)},
        "change": {"kind": "document.put", "value": {
            "collection": "charts", "document_id": "chart-1", "document": {"value": 1}
        }}
    })
}

fn resolve(value: &Value) -> Result<ResolvedMutation, Box<dyn Error>> {
    let request = MutationRequest::decode(&serde_json::to_vec(value)?)?;
    Ok(request.resolve("1001")?)
}

#[test]
fn exact_contract_keeps_the_declared_expected_version() -> TestResult {
    let request = resolve(&request_value())?;
    assert!(
        matches!(request.contract(), Contract::ExactVersion { expected } if *expected == version(2))
    );
    assert_eq!(request.origin(), version(2));
    Ok(())
}

#[test]
fn dependencies_keep_origin_and_absence_and_empty_interval_reads() -> TestResult {
    let mut value = request_value();
    value["contract"] = json!({"kind": "dependencies", "origin": version(1), "reads": [
        {"kind": "document", "collection": "charts", "document_id": "absent"},
        {"kind": "collection", "collection": "charts"},
        {"kind": "source_interval", "collection": "charts", "lower": "a", "upper": "a"}
    ]});
    let request = resolve(&value)?;
    let Contract::Dependencies { origin, reads } = request.contract() else {
        return Err("dependency contract was lost".into());
    };
    assert_eq!(*origin, version(1));
    assert_eq!(reads.len(), 3);
    assert_eq!(request.origin(), version(1));
    Ok(())
}

#[test]
fn missing_caller_resolves_to_the_socket_owner_without_changing_explicit_callers() -> TestResult {
    let mut value = request_value();
    let object = value.as_object_mut().ok_or("request is not an object")?;
    object.remove("caller");
    let request = MutationRequest::decode(&serde_json::to_vec(&value)?)?;
    let resolved = request.resolve("2048")?;
    assert_eq!(resolved.caller().issuer(), "local");
    assert_eq!(resolved.caller().subject(), "2048");
    let explicit =
        MutationRequest::decode(&serde_json::to_vec(&request_value())?)?.resolve("2048")?;
    assert_eq!(explicit.caller().subject(), "1001");
    Ok(())
}

#[test]
fn explicit_null_caller_never_becomes_the_socket_owner() -> TestResult {
    let mut value = request_value();
    value["caller"] = Value::Null;
    assert!(MutationRequest::decode(&serde_json::to_vec(&value)?).is_err());
    Ok(())
}

#[test]
fn omitted_and_explicit_owner_have_the_same_resolved_identity() -> TestResult {
    let explicit = request_value();
    let mut omitted = explicit.clone();
    omitted
        .as_object_mut()
        .ok_or("request is not an object")?
        .remove("caller");
    assert_eq!(
        resolve(&omitted)?.fingerprint()?,
        resolve(&explicit)?.fingerprint()?
    );
    Ok(())
}

#[test]
fn an_invalid_owner_is_never_assigned_to_an_anonymous_request() -> TestResult {
    let mut value = request_value();
    value
        .as_object_mut()
        .ok_or("request is not an object")?
        .remove("caller");
    let request = MutationRequest::decode(&serde_json::to_vec(&value)?)?;
    let error = request.resolve("").err().ok_or("invalid owner accepted")?;
    assert_eq!(error.code, "invalid_identifier");
    Ok(())
}

#[test]
fn responsible_person_survives_receipt_and_changes_request_identity() -> TestResult {
    let mut value = request_value();
    value["caller"]["responsible"] = json!("person-1");
    let first = resolve(&value)?;
    let receipt = Receipt::for_request(&first, version(3))?;
    let decoded = Receipt::decode(&serde_json::to_vec(&receipt)?)?;
    assert_eq!(decoded.caller().responsible(), Some("person-1"));
    value["caller"]["responsible"] = json!("person-2");
    assert_ne!(first.fingerprint()?, resolve(&value)?.fingerprint()?);
    Ok(())
}

#[test]
fn identity_limits_count_utf8_bytes_and_refuse_oversized_request_names() -> TestResult {
    let mut value = request_value();
    value["caller"]["subject"] = json!("é".repeat(256));
    assert!(MutationRequest::decode(&serde_json::to_vec(&value)?).is_ok());
    value["caller"]["subject"] = json!("é".repeat(257));
    assert!(MutationRequest::decode(&serde_json::to_vec(&value)?).is_err());
    let mut value = request_value();
    value["request_id"] = json!("x".repeat(513));
    assert!(MutationRequest::decode(&serde_json::to_vec(&value)?).is_err());
    Ok(())
}

#[test]
fn malformed_identity_and_credentials_are_refused_at_decode() -> TestResult {
    for caller in [
        json!({"issuer": "", "subject": "1001"}),
        json!({"issuer": "local", "subject": ""}),
        json!({"issuer": "local", "subject": "a\u{0000}b"}),
        json!({"issuer": "local", "subject": "1001", "responsible": ""}),
        json!({"issuer": "local", "subject": "1001", "token": "credential"}),
    ] {
        let mut value = request_value();
        value["caller"] = caller;
        assert!(MutationRequest::decode(&serde_json::to_vec(&value)?).is_err());
    }
    Ok(())
}

#[test]
fn old_top_level_expected_and_unknown_contract_fields_are_refused() -> TestResult {
    let mut old = request_value();
    let object = old.as_object_mut().ok_or("request is not an object")?;
    object.remove("contract");
    object.insert("expected".to_owned(), json!(version(2)));
    assert!(MutationRequest::decode(&serde_json::to_vec(&old)?).is_err());
    let mut unknown = request_value();
    unknown["contract"]["origin"] = json!(version(1));
    assert!(MutationRequest::decode(&serde_json::to_vec(&unknown)?).is_err());
    Ok(())
}

#[test]
fn unsupported_predicates_and_physical_root_dependencies_are_refused() -> TestResult {
    for read in [
        json!({"kind": "predicate", "expression": "value > 0"}),
        json!({"kind": "unique_index", "index": "identity", "key": "x"}),
        json!({"kind": "physical_root", "root": "00"}),
    ] {
        let mut value = request_value();
        value["contract"] = json!({"kind": "dependencies", "origin": version(1), "reads": [read]});
        assert!(MutationRequest::decode(&serde_json::to_vec(&value)?).is_err());
    }
    Ok(())
}

#[test]
fn reversed_intervals_and_invalid_dependency_names_are_refused() -> TestResult {
    for read in [
        json!({"kind": "source_interval", "collection": "charts", "lower": "z", "upper": "a"}),
        json!({"kind": "document", "collection": "charts", "document_id": ""}),
        json!({"kind": "collection", "collection": ""}),
    ] {
        let mut value = request_value();
        value["contract"] = json!({"kind": "dependencies", "origin": version(1), "reads": [read]});
        assert!(MutationRequest::decode(&serde_json::to_vec(&value)?).is_err());
    }
    Ok(())
}

#[test]
fn different_callers_reusing_a_request_id_never_receive_the_first_receipt() -> TestResult {
    let first = resolve(&request_value())?;
    let receipt = Receipt::for_request(&first, version(3))?;
    let mut value = request_value();
    value["caller"]["subject"] = json!("1002");
    let second = resolve(&value)?;
    assert_ne!(first.fingerprint()?, second.fingerprint()?);
    let error = receipt
        .replay(&second)
        .err()
        .ok_or("another caller received a receipt")?;
    assert_eq!(error.code, "request_id_reused");
    Ok(())
}

#[test]
fn unchanged_replay_preserves_original_origin_and_installed_version() -> TestResult {
    let mut value = request_value();
    value["contract"] = json!({"kind": "dependencies", "origin": version(1), "reads": []});
    let request = resolve(&value)?;
    let receipt = Receipt::for_request(&request, version(8))?;
    let encoded = serde_json::to_vec(&receipt)?;
    let decoded = Receipt::decode(&encoded)?;
    let replay = decoded.replay(&resolve(&value)?)?;
    assert_eq!(replay.request_origin(), version(1));
    assert_eq!(replay.version(), version(8));
    assert_eq!(serde_json::to_vec(replay)?, encoded);
    Ok(())
}

#[test]
fn branch_id_origin_contract_reads_and_change_all_bind_the_fingerprint() -> TestResult {
    let original = request_value();
    let fingerprint = resolve(&original)?.fingerprint()?;
    let changes = [
        ("request_id", json!("write-2")),
        ("branch", json!("other")),
        (
            "contract",
            json!({"kind": "exact_version", "expected": version(1)}),
        ),
        (
            "contract",
            json!({"kind": "dependencies", "origin": version(2), "reads": []}),
        ),
        (
            "change",
            json!({"kind": "document.delete", "value": {"collection": "charts", "document_id": "chart-1"}}),
        ),
    ];
    for (field, replacement) in changes {
        let mut value = original.clone();
        value[field] = replacement;
        assert_ne!(fingerprint, resolve(&value)?.fingerprint()?);
    }
    let mut dependencies = original;
    dependencies["contract"] = json!({"kind": "dependencies", "origin": version(1), "reads": []});
    let empty = resolve(&dependencies)?.fingerprint()?;
    dependencies["contract"]["reads"] = json!([{"kind": "collection", "collection": "charts"}]);
    assert_ne!(empty, resolve(&dependencies)?.fingerprint()?);
    Ok(())
}

#[test]
fn receipt_has_format_two_and_never_infers_a_missing_stored_author() -> TestResult {
    let request = resolve(&request_value())?;
    let receipt = Receipt::for_request(&request, version(3))?;
    let mut value = serde_json::to_value(&receipt)?;
    assert_eq!(value["format"], 2);
    assert_eq!(value["fingerprint_format"], 1);
    assert_eq!(value["contract_kind"], "exact_version");
    assert_eq!(value["request_origin"], json!(version(2)));
    value
        .as_object_mut()
        .ok_or("receipt is not an object")?
        .remove("caller");
    assert!(Receipt::decode(&serde_json::to_vec(&value)?).is_err());
    Ok(())
}

#[test]
fn old_and_future_receipt_formats_have_a_named_refusal() -> TestResult {
    let old = json!({"request_id": "write-1", "fingerprint": "00", "branch": "main", "version": version(3)});
    let error = Receipt::decode(&serde_json::to_vec(&old)?)
        .err()
        .ok_or("old receipt accepted")?;
    assert_eq!(error.code, "stored_receipt_format_unsupported");
    let request = resolve(&request_value())?;
    let mut future = serde_json::to_value(Receipt::for_request(&request, version(3))?)?;
    future["format"] = json!(3);
    let error = Receipt::decode(&serde_json::to_vec(&future)?)
        .err()
        .ok_or("future receipt accepted")?;
    assert_eq!(error.code, "stored_receipt_format_unsupported");
    Ok(())
}

#[test]
fn unsupported_fingerprint_format_and_noncanonical_digest_are_refused() -> TestResult {
    let request = resolve(&request_value())?;
    let original = serde_json::to_value(Receipt::for_request(&request, version(3))?)?;
    let mut future = original.clone();
    future["fingerprint_format"] = json!(2);
    let error = Receipt::decode(&serde_json::to_vec(&future)?)
        .err()
        .ok_or("future fingerprint accepted")?;
    assert_eq!(error.code, "stored_fingerprint_format_unsupported");
    for digest in ["00".to_owned(), "A".repeat(64), "g".repeat(64)] {
        let mut value = original.clone();
        value["fingerprint"] = json!(digest);
        assert!(Receipt::decode(&serde_json::to_vec(&value)?).is_err());
    }
    Ok(())
}

#[test]
fn a_receipt_from_another_key_is_corruption_not_a_replayed_answer() -> TestResult {
    let request = resolve(&request_value())?;
    let mut value = serde_json::to_value(Receipt::for_request(&request, version(3))?)?;
    value["request_id"] = json!("other-request");
    let receipt = Receipt::decode(&serde_json::to_vec(&value)?)?;
    let error = receipt.replay(&request).err().ok_or("wrong key replayed")?;
    assert_eq!(error.code, "receipt_corrupt");
    Ok(())
}

#[test]
fn tampering_with_the_stored_caller_never_returns_an_answer() -> TestResult {
    let request = resolve(&request_value())?;
    let mut value = serde_json::to_value(Receipt::for_request(&request, version(3))?)?;
    value["caller"]["subject"] = json!("1002");
    let receipt = Receipt::decode(&serde_json::to_vec(&value)?)?;
    let error = receipt
        .replay(&request)
        .err()
        .ok_or("altered caller replayed")?;
    assert_eq!(error.code, "request_id_reused");
    Ok(())
}

#[test]
fn fork_receipt_names_the_destination_and_keeps_the_source_origin() -> TestResult {
    let mut value = request_value();
    value["change"] = json!({"kind": "branch.fork", "value": {"name": "work", "from": version(1)}});
    let request = resolve(&value)?;
    let installed = Version {
        generation: 9,
        sequence: 0,
    };
    let receipt = Receipt::for_request(&request, installed)?;
    assert_eq!(receipt.branch(), "work");
    assert_eq!(receipt.request_origin(), version(2));
    assert_eq!(receipt.version(), installed);
    assert!(receipt.replay(&request).is_ok());
    Ok(())
}

#[test]
fn document_payload_bytes_are_preserved_and_part_of_identity() -> TestResult {
    let first = br#"{"request_id":"write-1","branch":"main","contract":{"kind":"exact_version","expected":{"generation":"7","sequence":"2"}},"change":{"kind":"document.put","value":{"collection":"charts","document_id":"chart-1","document":{ "z": 1.00, "a": 18446744073709551616001 }}}}"#;
    let second = br#"{"request_id":"write-1","branch":"main","contract":{"kind":"exact_version","expected":{"generation":"7","sequence":"2"}},"change":{"kind":"document.put","value":{"collection":"charts","document_id":"chart-1","document":{"z":1.00,"a":18446744073709551616001}}}}"#;
    let left = MutationRequest::decode(first)?.resolve("1001")?;
    let right = MutationRequest::decode(second)?.resolve("1001")?;
    let encoded = serde_json::to_string(&left)?;
    assert!(encoded.contains(r#"{ "z": 1.00, "a": 18446744073709551616001 }"#));
    assert_ne!(left.fingerprint()?, right.fingerprint()?);
    Ok(())
}