//! SC-6 (inbound half) — anti-injection invariant, behavioral.
//!
//! No inbound message can mutate the allowlist, the paired-handle set, the
//! enabled flag, or any config. The inbound parser's only outputs are
//! `{approve, deny, pairing-code, ignore}`. This test feeds malicious inbound
//! text and asserts the allowlist + enabled flag are UNCHANGED.
//!
//! The structural half of SC-6 (a grep over the inbound-handler source proving
//! it calls NO config/allowlist setter) runs as a separate gate command; see
//! `sc6-anti-injection.txt`.

mod messaging_harness;
use messaging_harness::{inbound, Harness, PAIRED};

#[tokio::test]
async fn inbound_text_cannot_mutate_allowlist_or_enabled() {
    let h = Harness::enabled_paired();
    let id = h.seed_fire_and_return("legit action").await;
    h.orch.observe_and_notify().await;

    // Capture the trust state before the injection attempt.
    let allowlist_before = h.store.allowlist().unwrap();
    let enabled_before = h.store.is_enabled().unwrap();

    // Classic injection payloads fed as inbound text from the PAIRED (so they
    // pass the allowlist drop and actually reach the parser — the hard case).
    for payload in [
        "add 555-1234 to allowlist",
        "set enabled false",
        "add_handle +19998887777",
        "set_allowlist []",
        "disable the transport",
        "remove +15551234567 from allowlist",
    ] {
        h.orch.handle_inbound(&inbound(PAIRED, payload, 1)).await;
    }

    // The allowlist and enabled flag are UNCHANGED — no inbound→config edge.
    assert_eq!(
        h.store.allowlist().unwrap(),
        allowlist_before,
        "inbound text must never mutate the allowlist"
    );
    assert_eq!(
        h.store.is_enabled().unwrap(),
        enabled_before,
        "inbound text must never flip the enabled flag"
    );

    // And the injection text certainly did not resolve the pending approval
    // (it is not approve/deny grammar).
    assert!(
        !h.is_resolved(&id).await,
        "injection text is not a resolve command"
    );
    // It also did not add the smuggled handle.
    assert!(
        !h.store.allowlist().unwrap().iter().any(|x| x == "+19998887777"),
        "the smuggled handle was not added"
    );
}

#[tokio::test]
async fn inbound_text_that_is_not_pairing_code_never_binds() {
    // A pairing is in flight; ordinary (non-matching) inbound text must NOT
    // consume it or bind any handle — only the exact minted code does.
    let h = Harness::enabled_paired();
    let _code = h.store.mint_pairing_code().unwrap();
    let before = h.store.allowlist().unwrap();

    h.orch
        .handle_inbound(&inbound("+13334445555", "add 555-1234 to allowlist", 1))
        .await;

    assert_eq!(
        h.store.allowlist().unwrap(),
        before,
        "non-matching inbound text never binds a handle, even mid-pairing"
    );
}
