unsafe-review-cli 0.3.6

CLI adapter for unsafe-review
Documentation
use serde_json::{Value, json};
use unsafe_review_core::ReviewCard;

use crate::lsp::TRUST_BOUNDARY;

pub(super) fn build_diagnostic_data(card: &ReviewCard) -> Value {
    json!({
        "card_id": &card.id.0,
        "operation": &card.operation.expression,
        "operation_family": card.operation.family.as_str(),
        "hazards": card.hazards.iter().map(|hazard| hazard.as_str()).collect::<Vec<_>>(),
        "required_safety_conditions": card.obligations.iter().map(|obligation| {
            json!({
                "key": &obligation.key,
                "description": &obligation.description
            })
        }).collect::<Vec<_>>(),
        "evidence_summary": {
            "contract": {
                "present": card.contract.present,
                "state": present_label(card.contract.present),
                "summary": &card.contract.summary
            },
            "discharge": {
                "present": card.discharge.present,
                "state": present_label(card.discharge.present),
                "summary": &card.discharge.summary
            },
            "reach": {
                "state": &card.reach.state,
                "summary": &card.reach.summary
            },
            "witness": {
                "present": card.witness.present,
                "state": present_label(card.witness.present),
                "summary": &card.witness.summary
            },
            "reach_limitation": "static reach evidence is not proof that the unsafe site executed"
        },
        "obligation_evidence": card.obligation_evidence.iter().map(|evidence| {
            json!({
                "key": &evidence.obligation.key,
                "description": &evidence.obligation.description,
                "contract": evidence_state(
                    evidence.contract.present,
                    &evidence.contract.state,
                    &evidence.contract.summary
                ),
                "discharge": evidence_state(
                    evidence.discharge.present,
                    &evidence.discharge.state,
                    &evidence.discharge.summary
                ),
                "reach": evidence_state(
                    evidence.reach.present,
                    &evidence.reach.state,
                    &evidence.reach.summary
                ),
                "witness": evidence_state(
                    evidence.witness.present,
                    &evidence.witness.state,
                    &evidence.witness.summary
                )
            })
        }).collect::<Vec<_>>(),
        "missing_evidence": card.missing.iter().map(|missing| missing.message.as_str()).collect::<Vec<_>>(),
        "next_action": &card.next_action.summary,
        "witness_routes": card.routes.iter().map(|route| {
            json!({
                "kind": route.kind.as_str(),
                "reason": &route.reason,
                "command": route.command.as_deref(),
                "required": route.required
            })
        }).collect::<Vec<_>>(),
        "verify_commands": &card.next_action.verify_commands,
        "trust_boundary": TRUST_BOUNDARY
    })
}

fn evidence_state(present: bool, state: &str, summary: &str) -> Value {
    json!({
        "present": present,
        "state": state,
        "summary": summary
    })
}

fn present_label(present: bool) -> &'static str {
    if present { "present" } else { "missing" }
}