harn-vm 0.10.167

Async bytecode virtual machine for the Harn programming language
Documentation
//! Inference boundary checks on the real loopback HTTP path.
use super::*;

#[test]
fn no_training_ceiling_plans_and_sends_only_required_controls() {
    use crate::llm::api::{
        preview_inference_admission, InferenceAdmissionRequest, InferenceAdmissionStatus,
    };
    use crate::llm_config::{DataPosture, RuntimeProviderEndpointOverrides};
    use std::io::Write;
    use std::sync::atomic::{AtomicUsize, Ordering};
    use std::sync::{Arc, Mutex};

    let _guard = env_guard();
    let _allow = allow_stubbed_llm_transport();
    let _cleanup = PrivacyOverrides;
    let counter = Arc::new(AtomicUsize::new(0));
    let captured = Arc::new(Mutex::new(Vec::new()));
    let requests = counter.clone();
    let bodies = captured.clone();
    let server = spawn_llm_stub_many("privacy controls", 5, move |_, stream| {
        let (_, body) = super::ollama_openai_compat::read_http_request(stream);
        let responses = body.get("input").is_some();
        bodies.lock().unwrap().push(body);
        requests.fetch_add(1, Ordering::SeqCst);
        let body = if responses {
            r#"{"status":"completed","output":[{"type":"message","role":"assistant","content":[{"type":"output_text","text":"accepted"}]}],"usage":{"input_tokens":3,"output_tokens":1,"total_tokens":4}}"#
        } else {
            r#"{"choices":[{"message":{"role":"assistant","content":"accepted"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3,"completion_tokens":1,"total_tokens":4}}"#
        };
        write!(stream, "HTTP/1.1 200 OK\r\ncontent-type: application/json\r\ncontent-length: {}\r\nconnection: close\r\n\r\n{body}", body.len()).unwrap();
    });
    crate::llm_config::set_runtime_provider_endpoint_overrides(
        RuntimeProviderEndpointOverrides::single("openrouter", format!("http://{}", server.addr()))
            .unwrap(),
    );
    let boundary = super::super::inference_boundary::InferenceBoundary {
        reach: super::super::inference_boundary::InferenceReach::AnyHosted,
        allow_training_discounts: false,
    };
    let _host_boundary = ScopedEnvVar::set(
        super::super::inference_boundary::HOST_BOUNDARY_ENV,
        serde_json::to_string(&boundary).unwrap(),
    );
    let runtime = tokio::runtime::Builder::new_current_thread()
        .enable_all()
        .build()
        .unwrap();
    let mut opts = base_opts("openrouter");
    opts.model = "google/gemini-3.5-flash-lite".into();
    opts.api_key = "invalid-test-key".into();
    opts.stream = false;
    opts.inference_boundary = None;
    for posture in [
        None,
        Some(DataPosture::Default),
        Some(DataPosture::StrictestAvailable),
    ] {
        opts.data_controls = posture;
        let before = counter.load(Ordering::SeqCst);
        let preview = preview_inference_admission(&InferenceAdmissionRequest {
            provider: opts.provider.clone(),
            model: opts.model.clone(),
            boundary: opts.inference_boundary,
            data_controls: posture,
        });
        assert_eq!(preview.status, InferenceAdmissionStatus::Admitted);
        assert!(preview.training_control_planned);
        assert_eq!(
            counter.load(Ordering::SeqCst),
            before,
            "preview never sends"
        );
        let result = runtime
            .block_on(vm_call_llm_full(&opts))
            .expect("required training control admits transport");
        assert_eq!(result.text, "accepted");
        assert_eq!(
            counter.load(Ordering::SeqCst),
            before + 1,
            "actual same listener reached"
        );
        let receipt = result.telemetry.data_controls.unwrap();
        assert_eq!(receipt.inference_boundary_rule, preview.governing_rule);
        assert_eq!(receipt.outcome, preview.data_controls_outcome.unwrap());
        let bodies = captured.lock().unwrap();
        let body = bodies.last().unwrap();
        assert_eq!(body["provider"]["data_collection"], "deny");
        if posture == Some(DataPosture::StrictestAvailable) {
            assert_eq!(body["provider"]["zdr"], true);
        } else {
            assert!(
                body["provider"].get("zdr").is_none(),
                "training ceiling adds no retention restriction"
            );
            assert_eq!(receipt.applied.len(), 1);
        }
    }

    let _without_host = ScopedEnvVar::remove(super::super::inference_boundary::HOST_BOUNDARY_ENV);
    opts.data_controls = Some(DataPosture::Default);
    let result = runtime
        .block_on(vm_call_llm_full(&opts))
        .expect("unbounded default still works");
    assert_eq!(counter.load(Ordering::SeqCst), 4);
    assert_eq!(
        result.telemetry.data_controls.unwrap().outcome,
        super::super::data_controls::DataControlsOutcome::NotRequested
    );
    let bodies = captured.lock().unwrap();
    let provider = &bodies.last().unwrap()["provider"];
    assert!(provider.get("data_collection").is_none());
    assert!(provider.get("zdr").is_none());
    drop(bodies);
    drop(_without_host);

    opts.inference_boundary = Some(boundary);
    let mut responses = crate::llm_config::provider_config("openrouter").unwrap();
    responses.features.push("responses_api".into());
    let mut overlay = crate::llm_config::ProvidersConfig::default();
    overlay.providers.insert("openrouter".into(), responses);
    crate::llm_config::set_user_overrides(Some(overlay));
    opts.api_mode = super::super::LlmApiMode::Responses;
    assert!(crate::llm_config::provider_has_feature(
        "openrouter",
        "responses_api"
    ));
    assert!(crate::llm::capabilities::should_use_responses_transport(
        &opts.provider,
        &opts.model,
        true
    ));
    let preflight = super::super::inference_boundary::preflight_chat(
        &super::super::LlmRequestPayload::from(&opts),
    );
    let result = runtime.block_on(vm_call_llm_full(&opts));
    assert_eq!(
        counter.load(Ordering::SeqCst),
        4,
        "Responses preflight_admitted={}, response_accepted={}, transmitted_without_training_control={}",
        preflight.is_ok(),
        result.as_ref().is_ok_and(|result| result.text == "accepted"),
        captured.lock().unwrap().last().unwrap()["provider"]
            .get("data_collection")
            .is_none()
    );
    assert!(preflight.is_err());
    assert!(result
        .expect_err("Responses cannot credit an unapplied training control")
        .to_string()
        .contains("inference_boundary.training_unknown"));
    opts.api_mode = super::super::LlmApiMode::ChatCompletions;
    crate::llm_config::clear_user_overrides();
    let mut definition = crate::llm_config::provider_config("openrouter").unwrap();
    for retention_only in [true, false] {
        if retention_only {
            definition
                .data_controls
                .as_mut()
                .unwrap()
                .request_controls
                .retain(|control| control.effect != crate::llm_config::DataControlEffect::Training);
        } else {
            definition
                .data_controls
                .as_mut()
                .unwrap()
                .request_controls
                .clear();
        }
        let mut overlay = crate::llm_config::ProvidersConfig::default();
        overlay
            .providers
            .insert("openrouter".into(), definition.clone());
        crate::llm_config::set_user_overrides(Some(overlay));
        let preview = preview_inference_admission(&InferenceAdmissionRequest {
            provider: opts.provider.clone(),
            model: opts.model.clone(),
            boundary: opts.inference_boundary,
            data_controls: opts.data_controls,
        });
        assert_eq!(preview.status, InferenceAdmissionStatus::Unknown);
        assert!(!preview.training_control_planned);
        let error = runtime
            .block_on(vm_call_llm_full(&opts))
            .expect_err("unknown without training control refuses");
        assert!(error
            .to_string()
            .contains("inference_boundary.training_unknown"));
        assert_eq!(
            counter.load(Ordering::SeqCst),
            4,
            "positive-controlled counter proves refusal before transport"
        );
    }
    crate::llm_config::clear_user_overrides();
    let mut native = crate::llm_config::provider_config("gemini").unwrap();
    native.data_controls = crate::llm_config::provider_config("openrouter")
        .unwrap()
        .data_controls;
    for control in &mut native.data_controls.as_mut().unwrap().request_controls {
        control.applies_to.clear();
    }
    let mut overlay = crate::llm_config::ProvidersConfig::default();
    overlay.providers.insert("gemini".into(), native);
    crate::llm_config::set_user_overrides(Some(overlay));
    opts.provider = "gemini".into();
    opts.model = "gemini-3.5-flash-lite".into();
    opts.data_controls = Some(DataPosture::StrictestAvailable);
    let preview = preview_inference_admission(&InferenceAdmissionRequest {
        provider: opts.provider.clone(),
        model: opts.model.clone(),
        boundary: opts.inference_boundary,
        data_controls: opts.data_controls,
    });
    assert_eq!(preview.status, InferenceAdmissionStatus::Unknown);
    assert!(
        !preview.training_control_planned,
        "native adapter cannot apply declared controls"
    );
    let error = runtime
        .block_on(vm_call_llm_full(&opts))
        .expect_err("native cannot credit unapplied controls");
    assert!(error
        .to_string()
        .contains("inference_boundary.training_unknown"));
    assert_eq!(counter.load(Ordering::SeqCst), 4);
    crate::llm_config::clear_user_overrides();
    opts.provider = "openrouter".into();
    opts.model = "google/gemini-3.5-flash-lite".into();
    opts.data_controls = Some(DataPosture::Default);
    opts.inference_boundary = None;
    let result = runtime
        .block_on(vm_call_llm_full(&opts))
        .expect("same listener remains live after refusals");
    assert_eq!(result.text, "accepted");
    assert_eq!(counter.load(Ordering::SeqCst), 5);
}

struct PrivacyOverrides;

impl Drop for PrivacyOverrides {
    fn drop(&mut self) {
        crate::llm_config::clear_user_overrides();
        crate::llm_config::clear_runtime_provider_endpoint_overrides();
    }
}

#[test]
fn host_local_ceiling_allows_loopback_transport_and_records_its_rule() {
    let _guard = env_guard();
    let _allow_llm_transport = allow_stubbed_llm_transport();
    let server = spawn_ollama_stub();
    let _ollama_host = ScopedEnvVar::set("OLLAMA_HOST", format!("http://{}", server.addr()));
    let _boundary = ScopedEnvVar::set(
        super::super::inference_boundary::HOST_BOUNDARY_ENV,
        r#"{"reach":"local_only","allow_training_discounts":false}"#,
    );
    let runtime = tokio::runtime::Builder::new_current_thread()
        .enable_all()
        .build()
        .expect("runtime");
    let result = runtime
        .block_on(vm_call_llm_full(&base_opts("ollama")))
        .expect("loopback route is allowed");
    assert_eq!(result.text, "hello world");
    assert_eq!(
        result.telemetry.inference_boundary_rule.as_deref(),
        Some("inference_boundary.local_runtime")
    );
    assert_eq!(
        result
            .telemetry
            .data_controls
            .as_ref()
            .and_then(|receipt| receipt.inference_boundary_rule.as_deref()),
        Some("inference_boundary.local_runtime")
    );
    let evidence = result
        .telemetry
        .data_controls
        .as_ref()
        .and_then(|receipt| receipt.inference_catalog_evidence.as_ref())
        .expect("allowed route records the catalog facts used by the rule");
    assert!(evidence.local_runtime);
    assert_eq!(evidence.open_weight, None);
}

#[test]
fn host_local_ceiling_refuses_hosted_chat_before_transport() {
    let _guard = env_guard();
    let _allow_llm_transport = allow_stubbed_llm_transport();
    let _boundary = ScopedEnvVar::set(
        super::super::inference_boundary::HOST_BOUNDARY_ENV,
        r#"{"reach":"local_only","allow_training_discounts":false}"#,
    );
    let _openai_base = ScopedEnvVar::set("OPENAI_BASE_URL", "http://127.0.0.1:9");
    let runtime = tokio::runtime::Builder::new_multi_thread()
        .worker_threads(1)
        .enable_all()
        .build()
        .expect("runtime");
    let mut opts = base_opts("openai");
    opts.api_key = "invalid-test-key".into();
    let error = runtime
        .block_on(vm_call_llm_full(&opts))
        .expect_err("host ceiling must refuse this hosted route");
    assert_local_policy_denial(&error);

    let local = tokio::task::LocalSet::new();
    let offthread = runtime.block_on(local.run_until(async {
        let (tx, _rx) = tokio::sync::mpsc::unbounded_channel();
        vm_call_llm_full_streaming_offthread(&opts, tx)
            .await
            .expect_err("off-thread dispatch must retain the host refusal")
    }));
    assert_local_policy_denial(&offthread);
}

fn assert_local_policy_denial(error: &crate::value::VmError) {
    let projected = crate::llm::call::build_llm_error_dict(error, "openai", "test-model");
    let crate::value::VmValue::Dict(fields) = projected else {
        panic!("the real call must project a structured denial");
    };
    let facts = crate::llm::helpers::vm_value_dict_to_json(&fields);
    assert_eq!(facts["reason"], "policy_denied");
    assert_eq!(facts["category"], "egress_blocked");
    assert_eq!(facts["origin"], "local");
    assert_eq!(facts["rule"], "inference_boundary.local_only");
    assert_eq!(facts["code"], "inference_boundary.local_only");
    assert_eq!(facts["retryable"], false);
    assert_eq!(
        crate::llm::agent_terminal_class("provider_error", "provider_error", Some(&facts)),
        Some(crate::llm::AgentTerminalClass::ToolPolicyRejected),
    );
}

#[test]
fn admission_preview_never_sends_and_the_same_listener_has_a_non_null_control() {
    use crate::llm::api::{
        preview_inference_admission, InferenceAdmissionRequest, InferenceAdmissionStatus,
    };
    use std::sync::atomic::{AtomicUsize, Ordering};
    use std::sync::Arc;

    let _guard = env_guard();
    let _allow = allow_stubbed_llm_transport();
    let counter = Arc::new(AtomicUsize::new(0));
    let server = spawn_ollama_empty_then_success_stub(counter.clone());
    let _endpoint = ScopedEnvVar::set("OLLAMA_HOST", format!("http://{}", server.addr()));
    let _boundary = ScopedEnvVar::set(
        super::super::inference_boundary::HOST_BOUNDARY_ENV,
        r#"{"reach":"local_only","allow_training_discounts":false}"#,
    );
    let opts = base_opts("ollama");
    let request = InferenceAdmissionRequest {
        provider: opts.provider.clone(),
        model: opts.model.clone(),
        boundary: None,
        data_controls: None,
    };
    assert_eq!(
        preview_inference_admission(&request).status,
        InferenceAdmissionStatus::Admitted
    );
    assert_eq!(counter.load(Ordering::SeqCst), 0);
    let runtime = tokio::runtime::Builder::new_current_thread()
        .enable_all()
        .build()
        .unwrap();
    let result = runtime
        .block_on(vm_call_llm_full(&opts))
        .expect("the real route must reach the listener");
    assert_eq!(result.text, "retried");
    let observed = counter.load(Ordering::SeqCst);
    assert!(
        observed > 0,
        "a measured zero needs the same counter's non-null control"
    );
    assert_eq!(
        preview_inference_admission(&request).status,
        InferenceAdmissionStatus::Admitted
    );
    assert_eq!(
        counter.load(Ordering::SeqCst),
        observed,
        "preview must not send another request"
    );
}