pub mod audit;
pub mod config_init;
pub mod fetch;
pub mod login;
pub mod logout;
pub mod policy;
pub mod risk_accept;
pub mod scan;
pub mod status;
pub mod verdict;
pub mod wrap;
use cleanlib_client::types;
pub fn scan_exit_code(decisions: &[types::PolicyDecision]) -> i32 {
let mut has_warn = false;
let mut has_risk = false;
for d in decisions {
match d.decision.as_str() {
"DENY" => return 1,
"WARN" => has_warn = true,
"RISK_ACCEPTANCE_REQUIRED" => has_risk = true,
_ => {}
}
}
if has_warn {
2
} else if has_risk {
3
} else {
0
}
}
pub fn verdict_exit_code(v: &types::Verdict) -> i32 {
let decision_str = v.decision.clone().unwrap_or_else(|| {
match v.verdict.as_str() {
"VECTOR_VERDICT" | "DM_THRESHOLD_BLOCK" => "DENY".to_string(),
"INSUFFICIENT_DATA" => "WARN".to_string(),
"ALLOWED_NO_FINDINGS" => "ALLOW".to_string(),
_ => "WARN".to_string(),
}
});
match decision_str.as_str() {
"DENY" => 1,
"WARN" => 2,
"RISK_ACCEPTANCE_REQUIRED" => 3,
_ => 0,
}
}
#[cfg(test)]
mod tests {
use super::*;
use cleanlib_client::types::{PolicyDecision, Verdict};
fn d(decision: &str) -> PolicyDecision {
PolicyDecision {
decision: decision.to_string(),
..PolicyDecision::default()
}
}
fn v_with_decision(decision: &str) -> Verdict {
Verdict {
decision: Some(decision.to_string()),
..Verdict::default()
}
}
fn v_with_label(label: &str) -> Verdict {
Verdict {
verdict: label.to_string(),
decision: None,
..Verdict::default()
}
}
#[test]
fn exit_zero_when_all_allow() {
assert_eq!(scan_exit_code(&[d("ALLOW"), d("ALLOW")]), 0);
}
#[test]
fn exit_one_on_any_deny() {
assert_eq!(scan_exit_code(&[d("ALLOW"), d("DENY"), d("WARN")]), 1);
}
#[test]
fn exit_two_on_warn_no_deny() {
assert_eq!(scan_exit_code(&[d("ALLOW"), d("WARN")]), 2);
}
#[test]
fn exit_three_on_risk_only() {
assert_eq!(scan_exit_code(&[d("ALLOW"), d("RISK_ACCEPTANCE_REQUIRED")]), 3);
}
#[test]
fn deny_dominates_risk() {
assert_eq!(scan_exit_code(&[d("RISK_ACCEPTANCE_REQUIRED"), d("DENY")]), 1);
}
#[test]
fn verdict_exit_zero_on_allow_decision() {
assert_eq!(verdict_exit_code(&v_with_decision("ALLOW")), 0);
}
#[test]
fn verdict_exit_one_on_deny_decision() {
assert_eq!(verdict_exit_code(&v_with_decision("DENY")), 1);
}
#[test]
fn verdict_exit_two_on_warn_decision() {
assert_eq!(verdict_exit_code(&v_with_decision("WARN")), 2);
}
#[test]
fn verdict_exit_three_on_risk_acceptance_required() {
assert_eq!(
verdict_exit_code(&v_with_decision("RISK_ACCEPTANCE_REQUIRED")),
3
);
}
#[test]
fn verdict_exit_one_on_vector_verdict_label_fallback() {
assert_eq!(verdict_exit_code(&v_with_label("VECTOR_VERDICT")), 1);
assert_eq!(verdict_exit_code(&v_with_label("DM_THRESHOLD_BLOCK")), 1);
}
#[test]
fn verdict_exit_zero_on_allowed_no_findings_label() {
assert_eq!(verdict_exit_code(&v_with_label("ALLOWED_NO_FINDINGS")), 0);
}
#[test]
fn verdict_exit_two_on_insufficient_data_label() {
assert_eq!(verdict_exit_code(&v_with_label("INSUFFICIENT_DATA")), 2);
}
#[test]
fn verdict_exit_two_on_unknown_label_fail_loud() {
assert_eq!(verdict_exit_code(&v_with_label("UNKNOWN_LABEL_XYZ")), 2);
}
}