use serde_json::{json, Value};
use super::Verdict;
const DEFAULT_DENY_REASON: &str = "Blocked by OpenLatch policy.";
const DECIDING: &[&str] = &["pre_tool_use", "user_prompt_submit"];
#[must_use]
pub fn translate(event: &str, verdict: &Verdict<'_>) -> Value {
if !DECIDING.contains(&event) {
return allow();
}
match (verdict.decision, verdict.context) {
("block" | "deny", Some(ctx)) => block(&format!("{}: {}", ctx.headline, ctx.body)),
("block" | "deny", None) => block(
verdict
.reason
.filter(|r| !r.trim().is_empty())
.unwrap_or(DEFAULT_DENY_REASON),
),
_ => allow(),
}
}
#[must_use]
pub fn translate_delivery(event: &str, verdict: &Verdict<'_>) -> Value {
translate(event, verdict)
}
fn allow() -> Value {
json!({ "decision": "allow" })
}
fn block(reason: &str) -> Value {
json!({ "decision": "block", "reason": reason })
}
#[cfg(test)]
mod tests {
use super::*;
fn v<'a>(decision: &'a str, reason: Option<&'a str>) -> Verdict<'a> {
Verdict {
decision,
reason,
context: None,
}
}
#[test]
fn a_block_on_a_deciding_event_carries_its_reason() {
for event in DECIDING {
assert_eq!(
translate(event, &v("block", Some("R-rm"))),
json!({"decision":"block","reason":"R-rm"})
);
assert_eq!(
translate(event, &v("deny", None)),
json!({"decision":"block","reason":DEFAULT_DENY_REASON})
);
assert_eq!(
translate(event, &v("block", Some(" "))),
json!({"decision":"block","reason":DEFAULT_DENY_REASON})
);
}
}
#[test]
fn ask_and_everything_else_is_allow_never_a_block() {
for decision in ["allow", "ask", "optimize", "approve", "whatever"] {
assert_eq!(
translate("pre_tool_use", &v(decision, Some("r"))),
json!({"decision":"allow"})
);
}
}
#[test]
fn a_record_only_event_never_blocks() {
for event in [
"post_tool_use",
"session_start",
"stop",
"session_end",
"plugin_loaded",
] {
assert_eq!(
translate(event, &v("block", Some("r"))),
json!({"decision":"allow"})
);
}
}
}