assay-sim 3.15.0

Simulation harness for Assay (internal, API unstable)
Documentation
use super::conditions::{
    vector1_condition_b, vector2_condition_b, vector3_condition_c, vector4_condition_b,
};
use super::controls::{
    control_b1_run_metadata_recall, control_b2_tool_observation_recall,
    control_b3_approval_context_recall,
};
use super::vectors::{
    vector1_replay_baseline_poisoning, vector2_deny_convergence_poisoning,
    vector3_context_envelope_poisoning, vector4_decay_escape,
};
use crate::attacks::memory_poison::{PoisonOutcome, PoisonResult};
use crate::report::{AttackResult, AttackStatus};
use std::time::Instant;

#[allow(clippy::too_many_arguments)]
pub(in crate::attacks::memory_poison) fn make_result(
    vector: &str,
    condition: &str,
    delay: u32,
    retained: bool,
    activated: bool,
    expected: &str,
    observed: &str,
    outcome: PoisonOutcome,
    tags: Vec<String>,
    start: Instant,
) -> (PoisonResult, AttackResult) {
    let pr = PoisonResult {
        vector_id: vector.to_string(),
        condition: condition.to_string(),
        phase_a_injected: true,
        phase_b_delay_turns: delay,
        phase_c_triggered: true,
        poison_retained: retained,
        activation_succeeded: activated,
        expected_classification: expected.to_string(),
        observed_classification: observed.to_string(),
        outcome: outcome.clone(),
        hypothesis_tags: tags,
    };
    let status = match &outcome {
        PoisonOutcome::ActivationWithMisclassification
        | PoisonOutcome::ActivationWithPolicyShift => AttackStatus::Bypassed,
        PoisonOutcome::ActivationWithCorrectDetection => AttackStatus::Blocked,
        _ => AttackStatus::Passed,
    };
    let ar = AttackResult {
        name: format!("memory_poison.{}.{}.delay_{}", vector, condition, delay),
        status,
        error_class: None,
        error_code: None,
        message: Some(format!(
            "expected={} observed={} outcome={:?}",
            expected, observed, outcome
        )),
        duration_ms: start.elapsed().as_millis() as u64,
    };
    (pr, ar)
}

pub(in crate::attacks::memory_poison) fn run_memory_poison_matrix(
) -> (Vec<PoisonResult>, Vec<AttackResult>) {
    let mut results = Vec::new();
    let mut attacks = Vec::new();

    for delay in [1, 2, 3] {
        let (pr, ar) = vector1_replay_baseline_poisoning(delay);
        results.push(pr);
        attacks.push(ar);
        let (pr, ar) = vector2_deny_convergence_poisoning(delay);
        results.push(pr);
        attacks.push(ar);
        let (pr, ar) = vector3_context_envelope_poisoning(delay);
        results.push(pr);
        attacks.push(ar);
        let (pr, ar) = vector4_decay_escape(delay);
        results.push(pr);
        attacks.push(ar);

        let (pr, ar) = vector1_condition_b(delay);
        results.push(pr);
        attacks.push(ar);
        let (pr, ar) = vector2_condition_b(delay);
        results.push(pr);
        attacks.push(ar);
        let (mut pr, mut ar) = vector3_context_envelope_poisoning(delay);
        pr.condition = "condition_b".to_string();
        ar.name = format!(
            "memory_poison.v3_context_envelope.condition_b.delay_{}",
            delay
        );
        results.push(pr);
        attacks.push(ar);
        let (pr, ar) = vector4_condition_b(delay);
        results.push(pr);
        attacks.push(ar);

        let (mut pr, mut ar) = vector1_condition_b(delay);
        pr.condition = "condition_c".to_string();
        ar.name = format!(
            "memory_poison.v1_replay_baseline.condition_c.delay_{}",
            delay
        );
        results.push(pr);
        attacks.push(ar);
        let (mut pr, mut ar) = vector2_condition_b(delay);
        pr.condition = "condition_c".to_string();
        ar.name = format!(
            "memory_poison.v2_deny_convergence.condition_c.delay_{}",
            delay
        );
        results.push(pr);
        attacks.push(ar);
        let (pr, ar) = vector3_condition_c(delay);
        results.push(pr);
        attacks.push(ar);
        let (mut pr, mut ar) = vector4_condition_b(delay);
        pr.condition = "condition_c".to_string();
        ar.name = format!("memory_poison.v4_decay_escape.condition_c.delay_{}", delay);
        results.push(pr);
        attacks.push(ar);

        let (pr, ar) = control_b1_run_metadata_recall(delay);
        results.push(pr);
        attacks.push(ar);
        let (pr, ar) = control_b2_tool_observation_recall(delay);
        results.push(pr);
        attacks.push(ar);
        let (pr, ar) = control_b3_approval_context_recall(delay);
        results.push(pr);
        attacks.push(ar);
    }

    (results, attacks)
}