cleanlib-cli 0.1.5

Terminal interface to CleanLibrary — query dependency verdicts and scan package manifests for ALLOW / DENY / WARN signals from the terminal or CI pipelines.
/// Three-tier render bucket for cross-surface consistency (cycle-7 entry §1.3).
/// Sister to `commands::scan_exit_code` — the wire enum vocab is broader (Phase
/// 1 has 5 distinct decision strings; cycle-7 envelope target is 3 tiers); the
/// CLI/Bash gate collapses to the 3-tier presentation layer.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(dead_code)]
pub enum DecisionTier {
    Allow,
    Warn,
    Deny,
    Other,
}
/// Map any `decision`/`verdict` string from either the Phase-1 wire vocab
/// or the cycle-7 envelope vocab into the 3-tier render bucket.
#[allow(dead_code)]
pub fn decision_tier(decision: &str) -> DecisionTier {
    match decision {
        // Cycle-7 universal envelope
        "ALLOW" => DecisionTier::Allow,
        "WARN" => DecisionTier::Warn,
        "DENY" => DecisionTier::Deny,
        // Phase-1 verdict vocab → tier mapping
        "ALLOWED_NO_FINDINGS" => DecisionTier::Allow,
        "VECTOR_VERDICT" | "DM_THRESHOLD_BLOCK" => DecisionTier::Deny,
        "RISK_ACCEPTANCE_REQUIRED" => DecisionTier::Warn,
        _ => DecisionTier::Other,
    }
}
/// Pick the decision tier string for rendering as the leading `decision:`
/// line. Derives from the verdict label first, then falls through to a
/// composite-score sniff for the unknown-label case (treat composite_score
/// >= 70 as DENY-tier signal until the label vocabulary catches up).
///
/// Prefer `decision_tier_str_with_severity` when the caller has access to
/// the `severity` field — it applies the severity-gated mapping for
/// `VECTOR_VERDICT` (HIGH/CRITICAL → DENY, MEDIUM/LOW/NONE → WARN) that
/// matches the extension's cycle-4 §D.7 logic and eliminates the
/// cross-surface verdict inconsistency fixed in CLEANLIB-270.
#[allow(dead_code)]
pub fn decision_tier_str(verdict_label: &str, composite_score: u8) -> &'static str {
    decision_tier_str_with_severity(verdict_label, None, composite_score)
}

/// Severity-aware variant of `decision_tier_str`. For `VECTOR_VERDICT` the
/// displayed decision tier is gated on severity to match the extension's
/// cycle-4 §D.7 policy (CLEANLIB-270 fix):
///
///   HIGH | CRITICAL → DENY
///   MEDIUM | LOW | NONE | unknown/absent → WARN
///
/// All other labels delegate to `decision_tier` as before.
#[allow(dead_code)]
pub fn decision_tier_str_with_severity(
    verdict_label: &str,
    severity: Option<&str>,
    composite_score: u8,
) -> &'static str {
    if verdict_label == "VECTOR_VERDICT" {
        return match severity.unwrap_or("").to_uppercase().as_str() {
            "HIGH" | "CRITICAL" => "DENY",
            _ => "WARN",
        };
    }
    match decision_tier(verdict_label) {
        DecisionTier::Allow => "ALLOW",
        DecisionTier::Warn => "WARN",
        DecisionTier::Deny => "DENY",
        DecisionTier::Other => {
            // Unknown / INSUFFICIENT_DATA — fail-closed per CLEANLIB-51:
            // surface as WARN with a high-score override to DENY.
            if composite_score >= 70 {
                "DENY"
            } else {
                "WARN"
            }
        }
    }
}