canic-host 0.68.0

Host-side build, install, deployment, and fleet-template library for Canic workspaces
Documentation
use super::*;

#[test]
fn promotion_plan_transform_evidence_validation_accepts_generated_evidence() {
    let request = PromotionPlanTransformRequest {
        promoted_plan_id: "promoted-plan-1".to_string(),
        target_plan: sample_promotion_target_plan(),
        inputs: vec![sample_role_promotion_input(
            PromotionArtifactLevelV1::SealedWasm,
        )],
    };
    let transform = promoted_deployment_plan_transform_from_inputs(&request)
        .expect("transform should be produced");
    let evidence = promotion_plan_transform_evidence(PromotionPlanTransformEvidenceRequest {
        evidence_id: "promotion-evidence-1".to_string(),
        generated_at: "2026-05-25T00:00:00Z".to_string(),
        transform,
    })
    .expect("evidence should be produced");

    validate_promotion_plan_transform_evidence(&evidence)
        .expect("generated evidence should validate");
}

#[test]
fn promotion_plan_transform_evidence_text_reports_passive_boundary() {
    let mut target_plan = sample_promotion_target_plan();
    target_plan.role_artifacts[0].wasm_gz_sha256 = Some(sample_sha256("f"));
    let mut input = sample_role_promotion_input(PromotionArtifactLevelV1::SealedWasm);
    input.require_byte_identical_wasm = false;
    let transform =
        promoted_deployment_plan_transform_from_inputs(&PromotionPlanTransformRequest {
            promoted_plan_id: "promoted-plan-1".to_string(),
            target_plan,
            inputs: vec![input],
        })
        .expect("transform should be produced");
    let evidence = promotion_plan_transform_evidence(PromotionPlanTransformEvidenceRequest {
        evidence_id: "promotion-evidence-1".to_string(),
        generated_at: "2026-05-25T00:00:00Z".to_string(),
        transform,
    })
    .expect("evidence should be produced");

    let text = promotion_plan_transform_evidence_text(&evidence);

    assert!(text.contains("Promotion plan transform evidence"));
    assert!(text.contains("mode: passive"));
    assert!(text.contains("execution: none"));
    assert!(text.contains("evidence_id: promotion-evidence-1"));
    assert!(text.contains("promotion_plan_transform_evidence_digest:"));
    assert!(text.contains("generated_at: 2026-05-25T00:00:00Z"));
    assert!(text.contains("transform_id: promotion-transform:promoted-plan-1"));
    assert!(text.contains("  Promotion plan transform"));
    assert!(text.contains("  mode: passive"));
    assert!(text.contains("  artifact_identity_changed: 1"));
}

#[test]
fn promotion_plan_transform_evidence_validation_rejects_blank_evidence_id() {
    let request = PromotionPlanTransformRequest {
        promoted_plan_id: "promoted-plan-1".to_string(),
        target_plan: sample_promotion_target_plan(),
        inputs: vec![sample_role_promotion_input(
            PromotionArtifactLevelV1::SealedWasm,
        )],
    };
    let transform = promoted_deployment_plan_transform_from_inputs(&request)
        .expect("transform should be produced");
    let err = promotion_plan_transform_evidence(PromotionPlanTransformEvidenceRequest {
        evidence_id: " ".to_string(),
        generated_at: "2026-05-25T00:00:00Z".to_string(),
        transform,
    })
    .expect_err("blank evidence id should fail");

    std::assert_matches!(
        err,
        PromotionPlanTransformEvidenceError::MissingRequiredField {
            field: "evidence_id"
        }
    );
}

#[test]
fn promotion_plan_transform_evidence_validation_rejects_schema_drift() {
    let request = PromotionPlanTransformRequest {
        promoted_plan_id: "promoted-plan-1".to_string(),
        target_plan: sample_promotion_target_plan(),
        inputs: vec![sample_role_promotion_input(
            PromotionArtifactLevelV1::SealedWasm,
        )],
    };
    let transform = promoted_deployment_plan_transform_from_inputs(&request)
        .expect("transform should be produced");
    let mut evidence = promotion_plan_transform_evidence(PromotionPlanTransformEvidenceRequest {
        evidence_id: "promotion-evidence-1".to_string(),
        generated_at: "2026-05-25T00:00:00Z".to_string(),
        transform,
    })
    .expect("evidence should be produced");
    evidence.schema_version += 1;

    let err = validate_promotion_plan_transform_evidence(&evidence)
        .expect_err("schema drift should fail");
    std::assert_matches!(
        err,
        PromotionPlanTransformEvidenceError::SchemaVersionMismatch { .. }
    );
}

#[test]
fn promotion_plan_transform_evidence_validation_rejects_stale_digest() {
    let request = PromotionPlanTransformRequest {
        promoted_plan_id: "promoted-plan-1".to_string(),
        target_plan: sample_promotion_target_plan(),
        inputs: vec![sample_role_promotion_input(
            PromotionArtifactLevelV1::SealedWasm,
        )],
    };
    let transform = promoted_deployment_plan_transform_from_inputs(&request)
        .expect("transform should be produced");
    let mut evidence = promotion_plan_transform_evidence(PromotionPlanTransformEvidenceRequest {
        evidence_id: "promotion-evidence-1".to_string(),
        generated_at: "2026-05-25T00:00:00Z".to_string(),
        transform,
    })
    .expect("evidence should be produced");
    evidence.promotion_plan_transform_evidence_digest = sample_sha256("9");

    let err = validate_promotion_plan_transform_evidence(&evidence)
        .expect_err("stale evidence digest should fail");
    std::assert_matches!(
        err,
        PromotionPlanTransformEvidenceError::LinkageMismatch {
            field: "promotion_plan_transform_evidence_digest"
        }
    );
}

#[test]
fn promotion_plan_transform_evidence_validation_rejects_stale_transform() {
    let request = PromotionPlanTransformRequest {
        promoted_plan_id: "promoted-plan-1".to_string(),
        target_plan: sample_promotion_target_plan(),
        inputs: vec![sample_role_promotion_input(
            PromotionArtifactLevelV1::SealedWasm,
        )],
    };
    let transform = promoted_deployment_plan_transform_from_inputs(&request)
        .expect("transform should be produced");
    let mut evidence = promotion_plan_transform_evidence(PromotionPlanTransformEvidenceRequest {
        evidence_id: "promotion-evidence-1".to_string(),
        generated_at: "2026-05-25T00:00:00Z".to_string(),
        transform,
    })
    .expect("evidence should be produced");
    evidence.transform.roles[0].artifact_identity_changed = false;

    let err = validate_promotion_plan_transform_evidence(&evidence)
        .expect_err("stale transform should fail");
    std::assert_matches!(
        err,
        PromotionPlanTransformEvidenceError::Transform(
            PromotionPlanTransformError::RoleStateMismatch {
                role,
                field: "artifact_identity_changed"
            }
        ) if role == "root"
    );
}