haematite-cli 0.21.3

The haematite command: serve a store, its door and Studio, answer MCP, query with jq, and host the store's assistant seat
Documentation
use super::receipt_fragments::{
    Assembler, EncodedReceipt, FragmentEnvelope, FragmentPart, ReceiptCodecError, minimum_cap,
    reserve_bytes,
};
use super::receipt_wire::WireReceipt;
use super::receipt_wire_tests::fixture;
use std::error::Error;

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

fn encoded() -> Result<EncodedReceipt, Box<dyn Error>> {
    let encoded = EncodedReceipt::project(&fixture()?, None)?;
    Ok(encoded)
}

#[test]
fn complete_receipt_roundtrips_through_real_bounded_frames() -> TestResult {
    let encoded = encoded()?;
    let cap = u32::try_from(minimum_cap()?)?;
    assert!(encoded.bytes().len() > usize::try_from(cap)?);
    let frames = encoded.frames("haem-call", cap)?;
    assert!(frames.len() > 2);
    let limit = std::num::NonZeroU32::new(cap).ok_or("receipt cap is zero")?;
    let mut transport = Vec::new();
    for body in &frames {
        super::frame::write(&mut transport, body, limit)?;
    }
    let mut input = std::io::Cursor::new(transport);
    let mut assembler = Assembler::new("haem-call", cap)?;
    let mut result = None;
    while let Some(body) = super::frame::read(&mut input, limit)? {
        let next = assembler.accept(&body)?;
        if next.is_some() {
            assert!(result.is_none());
            result = next;
        }
    }
    let complete = result.ok_or("assembler never completed the receipt")?;
    let receipt = complete.receipt().ok_or("packet has no receipt")?;
    assert_eq!(receipt, &WireReceipt::project(&fixture()?)?);
    Ok(())
}

#[test]
fn low_cap_names_both_actual_numbers() -> TestResult {
    let minimum = minimum_cap()?;
    let offered = u32::try_from(minimum - 1)?;
    let Err(error) = encoded()?.frames("haem-call", offered) else {
        return Err("frames accepted a cap below the minimum".into());
    };
    assert!(
        matches!(error, ReceiptCodecError::FrameTooSmall { offered: n, minimum: m } if n == offered && m == minimum)
    );
    let message = error.to_string();
    assert!(message.contains("receipt_frame_too_small"));
    assert!(message.contains(&offered.to_string()));
    assert!(message.contains(&minimum.to_string()));
    Ok(())
}

fn change(
    frame: &[u8],
    mutate: impl FnOnce(&mut FragmentEnvelope) -> TestResult,
) -> Result<Vec<u8>, Box<dyn Error>> {
    let mut envelope: FragmentEnvelope = serde_json::from_slice(frame)?;
    mutate(&mut envelope)?;
    let changed = serde_json::to_vec(&envelope)?;
    Ok(changed)
}

#[test]
fn dropped_duplicate_and_out_of_order_fragments_never_complete() -> TestResult {
    let cap = u32::try_from(minimum_cap()?)?;
    let frames = encoded()?.frames("id", cap)?;
    let mut missing = Assembler::new("id", cap)?;
    missing.accept(&frames[0])?;
    assert!(matches!(
        missing.accept(&frames[2]),
        Err(ReceiptCodecError::Sequence { .. })
    ));
    assert!(matches!(
        missing.connection_closed(),
        Err(ReceiptCodecError::ConnectionClosed)
    ));
    let mut duplicate = Assembler::new("id", cap)?;
    duplicate.accept(&frames[0])?;
    assert!(matches!(
        duplicate.accept(&frames[0]),
        Err(ReceiptCodecError::Sequence { .. })
    ));
    let mut order = Assembler::new("id", cap)?;
    assert!(matches!(
        order.accept(&frames[1]),
        Err(ReceiptCodecError::Sequence { .. })
    ));
    Ok(())
}

#[test]
fn terminal_digest_count_and_extent_are_verified() -> TestResult {
    let cap = u32::try_from(minimum_cap()?)?;
    let frames = encoded()?.frames("id", cap)?;
    let terminal = frames.last().ok_or("encoded receipt has no frames")?;
    for fault in 0..3 {
        let last = change(terminal, |e| {
            let FragmentPart::End {
                digest,
                outcomes,
                bytes,
                ..
            } = &mut e.part
            else {
                return Err("terminal missing".into());
            };
            match fault {
                0 => *digest = "00".repeat(32),
                1 => *outcomes += 1,
                2 => *bytes += 1,
                _ => unreachable!(),
            }
            Ok(())
        })?;
        let mut assembler = Assembler::new("id", cap)?;
        for frame in &frames[..frames.len() - 1] {
            assert!(assembler.accept(frame)?.is_none());
        }
        let Err(error) = assembler.accept(&last) else {
            return Err("a tampered terminal fragment was accepted".into());
        };
        assert!(matches!(
            (fault, error),
            (0, ReceiptCodecError::Digest)
                | (1, ReceiptCodecError::Count { .. })
                | (2, ReceiptCodecError::Extent { .. })
        ));
        assert!(matches!(
            assembler.connection_closed(),
            Err(ReceiptCodecError::ConnectionClosed)
        ));
    }
    Ok(())
}

#[test]
fn allocation_refusal_uses_actual_checked_reservation() {
    let mut bytes = Vec::new();
    assert!(matches!(
        reserve_bytes(&mut bytes, usize::MAX),
        Err(ReceiptCodecError::Allocation { .. })
    ));
    assert!(bytes.is_empty());
}

#[test]
fn connection_close_id_hex_decode_and_missing_terminal_are_named() -> TestResult {
    let cap = u32::try_from(minimum_cap()?)?;
    let frames = encoded()?.frames("id", cap)?;
    let mut closed = Assembler::new("id", cap)?;
    closed.accept(&frames[0])?;
    assert!(matches!(
        closed.connection_closed(),
        Err(ReceiptCodecError::ConnectionClosed)
    ));
    let mut wrong_id = Assembler::new("other", cap)?;
    assert!(matches!(
        wrong_id.accept(&frames[0]),
        Err(ReceiptCodecError::Identity)
    ));
    let invalid = change(&frames[0], |e| {
        let FragmentPart::Chunk { hex, .. } = &mut e.part else {
            return Err("chunk missing".into());
        };
        *hex = "gg".into();
        Ok(())
    })?;
    assert!(matches!(
        Assembler::new("id", cap)?.accept(&invalid),
        Err(ReceiptCodecError::Hex)
    ));
    assert!(matches!(
        Assembler::new("id", cap)?.accept(b"not json"),
        Err(ReceiptCodecError::Decode { .. })
    ));
    Ok(())
}

#[test]
fn worst_valid_identity_fits_the_derived_floor() -> TestResult {
    let id = "\0".repeat(512);
    let cap = u32::try_from(minimum_cap()?)?;
    let frames = encoded()?.frames(&id, cap)?;
    let mut assembler = Assembler::new(&id, cap)?;
    let mut result = None;
    for frame in frames {
        assert!(frame.len() <= usize::try_from(cap)?);
        if let Some(receipt) = assembler.accept(&frame)? {
            result = Some(receipt);
        }
    }
    assert!(result.is_some());
    assert!(assembler.connection_closed().is_ok());
    assert!(matches!(
        assembler.accept(b"{}"),
        Err(ReceiptCodecError::Finished)
    ));
    Ok(())
}

#[test]
fn incomplete_terminal_invalid_identity_and_frame_limit_are_refused() -> TestResult {
    let cap = u32::try_from(minimum_cap()?)?;
    assert!(matches!(
        Assembler::new("", cap),
        Err(ReceiptCodecError::InvalidId)
    ));
    assert!(matches!(
        Assembler::new(&"x".repeat(513), cap),
        Err(ReceiptCodecError::InvalidId)
    ));
    let terminal = serde_json::to_vec(&FragmentEnvelope {
        id: "id".into(),
        part: FragmentPart::End {
            fragments: 0,
            outcomes: 0,
            bytes: 0,
            digest: "00".repeat(32),
        },
    })?;
    assert!(matches!(
        Assembler::new("id", cap)?.accept(&terminal),
        Err(ReceiptCodecError::Incomplete)
    ));
    let oversized = vec![b' '; usize::try_from(cap)? + 1];
    assert!(matches!(
        Assembler::new("id", cap)?.accept(&oversized),
        Err(ReceiptCodecError::FrameLimit { .. })
    ));
    let mut nonempty = vec![1];
    assert!(matches!(
        reserve_bytes(&mut nonempty, usize::MAX),
        Err(ReceiptCodecError::ExtentOverflow)
    ));
    Ok(())
}

#[test]
fn verified_bytes_must_decode_as_a_complete_typed_receipt() -> TestResult {
    use sha2::{Digest, Sha256};
    let bytes = b"{";
    let digest = super::receipt_fragments::encode_hex(&Sha256::digest(bytes))?;
    let cap = u32::try_from(minimum_cap()?)?;
    let chunk = serde_json::to_vec(&FragmentEnvelope {
        id: "id".into(),
        part: FragmentPart::Chunk {
            sequence: 0,
            hex: "7b".into(),
        },
    })?;
    let terminal = serde_json::to_vec(&FragmentEnvelope {
        id: "id".into(),
        part: FragmentPart::End {
            fragments: 1,
            outcomes: 0,
            bytes: 1,
            digest,
        },
    })?;
    let mut assembler = Assembler::new("id", cap)?;
    assert!(assembler.accept(&chunk)?.is_none());
    assert!(matches!(
        assembler.accept(&terminal),
        Err(ReceiptCodecError::Decode { .. })
    ));
    Ok(())
}

#[test]
fn verified_receipt_retains_the_exact_once_serialized_bytes() -> TestResult {
    let encoded = encoded()?;
    let cap = u32::try_from(minimum_cap()?)?;
    let mut assembler = Assembler::new("sealed", cap)?;
    let mut complete = None;
    for frame in encoded.frames("sealed", cap)? {
        if let Some(receipt) = assembler.accept(&frame)? {
            assert!(complete.is_none());
            complete = Some(receipt);
        }
    }
    let complete = complete.ok_or("assembler never completed the receipt")?;
    assert_eq!(complete.bytes(), encoded.bytes());
    let receipt = complete.receipt().ok_or("packet has no receipt")?;
    assert_eq!(receipt, &WireReceipt::project(&fixture()?)?);
    assert!(assembler.connection_closed().is_ok());
    assert_eq!(complete.bytes(), encoded.bytes());
    Ok(())
}

#[test]
fn verified_receipt_retains_lossless_noncanonical_json_bytes() -> TestResult {
    use sha2::{Digest, Sha256};
    let bytes = b"{ \"kind\": \"receipt\", \"receipt\": { \"outcomes\": [], \"submit_error\": null, \"first_error\": null }, \"refusal\": null }\n";
    let digest = super::receipt_fragments::encode_hex(&Sha256::digest(bytes))?;
    let cap = u32::try_from(minimum_cap()?)?;
    let mut assembler = Assembler::new("exact", cap)?;
    let chunk = serde_json::to_vec(&FragmentEnvelope {
        id: "exact".into(),
        part: FragmentPart::Chunk {
            sequence: 0,
            hex: super::receipt_fragments::encode_hex(bytes)?,
        },
    })?;
    let end = serde_json::to_vec(&FragmentEnvelope {
        id: "exact".into(),
        part: FragmentPart::End {
            fragments: 1,
            outcomes: 0,
            bytes: u64::try_from(bytes.len())?,
            digest,
        },
    })?;
    assert!(assembler.accept(&chunk)?.is_none());
    let complete = assembler.accept(&end)?.ok_or("terminal did not complete")?;
    assert_eq!(complete.bytes(), bytes);
    let receipt = complete.receipt().ok_or("packet has no receipt")?;
    assert!(receipt.outcomes.is_empty());
    assert_ne!(serde_json::to_vec(complete.packet())?, bytes);
    Ok(())
}