khive-runtime 0.13.0

Composable Service API: entity/note CRUD, graph traversal, hybrid search, curation.
Documentation
use super::{check_note_fields_at, scan};
use crate::atomic_message::{create_notes_atomic, AtomicNoteSpec};
use crate::{KhiveRuntime, Namespace, RuntimeError};
use serde_json::json;

const SECRET: &str = "AKIAFAKEKEY1234567890";

fn assert_secret(error: RuntimeError, location: &str) {
    let RuntimeError::SecretDetected(matched) = error else {
        panic!("expected secret refusal at {location}, got {error:?}");
    };
    let mut expected = scan(SECRET).expect("known credential fixture");
    expected.location = Some(location.to_owned());
    assert_eq!(matched, expected);
}

#[test]
fn note_fields_preserve_first_refusal_and_structured_property_location() {
    let properties = json!({"nested": [null, {"value": SECRET}]});
    for (content, name, field) in [
        (SECRET, Some(SECRET), "content"),
        ("ordinary text", Some(SECRET), "name"),
        ("ordinary text", None, "properties"),
    ] {
        let error = check_note_fields_at(content, name, Some(&properties), "note[3]")
            .expect_err("first secret-bearing field must refuse");
        assert_secret(error, &format!("note[3].{field}"));
    }
}

#[test]
fn note_fields_accept_optional_and_benign_structured_values_without_reservation_policy() {
    assert!(check_note_fields_at("ordinary text", None, None, "note").is_ok());
    for properties in [
        json!(null),
        json!({"nested": [null, true, 7, {"path": "docs/guide.md"}]}),
        json!({"khive:secret_gate": true}),
    ] {
        assert!(
            check_note_fields_at("ordinary text", Some("title"), Some(&properties), "note").is_ok()
        );
    }
}

#[tokio::test]
async fn note_writers_keep_reserved_key_before_field_scan() {
    let runtime = KhiveRuntime::memory().unwrap();
    let token = runtime
        .authorize(Namespace::parse("local").unwrap())
        .unwrap();
    for reserved in [true, false] {
        let properties = reserved.then(|| json!({"khive:secret_gate": true}));
        let errors = [
            runtime
                .create_note(
                    &token,
                    "observation",
                    Some(SECRET),
                    SECRET,
                    None,
                    properties.clone(),
                    vec![],
                )
                .await
                .unwrap_err(),
            runtime
                .try_create_note(
                    &token,
                    "observation",
                    Some(SECRET),
                    SECRET,
                    properties.clone(),
                )
                .await
                .unwrap_err(),
            create_notes_atomic(
                &runtime,
                vec![AtomicNoteSpec {
                    token: &token,
                    id: None,
                    kind: "observation",
                    name: Some(SECRET),
                    content: SECRET,
                    properties,
                }],
            )
            .await
            .unwrap_err(),
        ];
        for (index, error) in errors.into_iter().enumerate() {
            if reserved {
                assert!(matches!(error, RuntimeError::InvalidInput(ref message)
                    if message.contains("khive:secret_gate") && message.contains("runtime-owned")));
            } else {
                assert_secret(
                    error,
                    if index == 2 {
                        "note[0].content"
                    } else {
                        "note.content"
                    },
                );
            }
        }
    }
    assert!(runtime
        .list_notes(&token, None, 10, 0)
        .await
        .unwrap()
        .is_empty());
}

#[tokio::test]
async fn atomic_note_scan_locates_later_record_before_any_write() {
    let runtime = KhiveRuntime::memory().unwrap();
    let token = runtime
        .authorize(Namespace::parse("local").unwrap())
        .unwrap();
    let error = create_notes_atomic(
        &runtime,
        vec![
            AtomicNoteSpec {
                token: &token,
                id: None,
                kind: "observation",
                name: None,
                content: "ordinary first note",
                properties: None,
            },
            AtomicNoteSpec {
                token: &token,
                id: None,
                kind: "observation",
                name: Some(SECRET),
                content: "ordinary second note",
                properties: Some(json!({"nested": [SECRET]})),
            },
        ],
    )
    .await
    .unwrap_err();
    assert_secret(error, "note[1].name");
    assert!(runtime
        .list_notes(&token, None, 10, 0)
        .await
        .unwrap()
        .is_empty());
}

#[tokio::test]
async fn proposal_note_preparation_keeps_field_scan_before_reserved_key() {
    let runtime = KhiveRuntime::memory().unwrap();
    let token = runtime
        .authorize(Namespace::parse("local").unwrap())
        .unwrap();
    let mut args = json!({"kind": "observation", "content": SECRET,
        "properties": {"khive:secret_gate": true}});
    let error = crate::atomic_prepare::prepare_add_note(&runtime, &token, &args)
        .await
        .unwrap_err();
    assert_secret(error, "note.content");
    args["content"] = json!("ordinary text");
    let error = crate::atomic_prepare::prepare_add_note(&runtime, &token, &args)
        .await
        .unwrap_err();
    assert!(matches!(error, RuntimeError::InvalidInput(ref message)
        if message.contains("khive:secret_gate") && message.contains("runtime-owned")));
}