use super::*;
use crate::control::judge::Table;
use crate::control::policy::Policy;
use crate::opslog::Origin;
use serde_json::json;
fn at(cwd: &str, words: &[&str]) -> OpEntry {
OpEntry {
ts: "TS".to_owned(),
argv: words.iter().map(|s| (*s).to_owned()).collect(),
cwd: cwd.to_owned(),
exit: 0,
stdout: String::new(),
stderr: String::new(),
origin: Origin::World,
client: crate::registry::Client::default(),
}
}
fn row(words: &[&str]) -> OpEntry {
at("", words)
}
fn call(id: &str, name: &str, agent: &str) -> Request {
Request {
id: id.to_owned(),
name: name.to_owned(),
input: json!({}),
role: "worker".to_owned(),
agent_id: agent.to_owned(),
}
}
fn ruling(answers: &Answers, request: &Request, ws: &str, effect: Effect) -> Standing {
answers.ruling(request, ws, effect, &Policy::default())
}
#[test]
fn an_unanswered_invocation_is_the_table_s_verdict_at_workspace_scope() {
let answers = Answers::fold(&[]);
let call = call("toolu_1", "bash", "amber");
assert_eq!(
ruling(&answers, &call, "w", Effect::OpenWorld),
Standing {
ruling: Ruling::Pass,
scope: Scope::Workspace
}
);
assert_eq!(
answers
.ruling(
&call,
"w",
Effect::OpenWorld,
&Policy::parse("table:\n open-world: hold\n")
)
.ruling,
Ruling::Hold
);
}
#[test]
fn a_call_answer_is_scoped_to_the_held_tool_use_id() {
let answers = Answers::fold(&[
row(&[YOG_CONTROL, "answer", "toolu_1", "pass", "call"]),
row(&[YOG_CONTROL, "answer", "toolu_2", "refuse"]),
]);
assert_eq!(
ruling(
&answers,
&call("toolu_1", "bash", "amber"),
"w",
Effect::Destructive
),
Standing {
ruling: Ruling::Pass,
scope: Scope::Call
}
);
assert_eq!(
ruling(
&answers,
&call("toolu_2", "bash", "amber"),
"w",
Effect::Read
)
.ruling,
Ruling::Refuse
);
assert_eq!(
ruling(
&answers,
&call("toolu_3", "bash", "amber"),
"w",
Effect::Destructive
),
Standing {
ruling: Table::ruling(Effect::Destructive),
scope: Scope::Workspace
}
);
}
#[test]
fn the_last_row_for_a_key_wins_at_every_scope() {
let answers = Answers::fold(&[
row(&[YOG_CONTROL, "answer", "toolu_1", "pass", "call"]),
row(&[YOG_CONTROL, "answer", "toolu_1", "refuse", "call"]),
at(
"ws",
&[YOG_CONTROL, "answer", "bash@read", "pass", "workspace"],
),
at(
"ws",
&[YOG_CONTROL, "answer", "bash@read", "refuse", "workspace"],
),
]);
assert_eq!(
ruling(&answers, &call("toolu_1", "bash", "a"), "ws", Effect::Read).ruling,
Ruling::Refuse
);
assert_eq!(
ruling(&answers, &call("toolu_2", "bash", "a"), "ws", Effect::Read).ruling,
Ruling::Refuse,
"the standing answer is superseded, not doubled"
);
}
#[test]
fn a_routed_refusal_is_addressed_to_the_operator_as_a_hold() {
let answers = Answers::fold(&[]);
let at = |name: &str, effect| ruling(&answers, &call("t1", name, "amber"), "w", effect).ruling;
assert_eq!(at("bash", Effect::Destructive), Ruling::Refuse);
assert_eq!(at("bash", Effect::Secret), Ruling::Refuse);
assert_eq!(at("box2_shell", Effect::Destructive), Ruling::Hold);
assert_eq!(at("box2_shell", Effect::Secret), Ruling::Hold);
assert_eq!(at("box2_shell", Effect::OpenWorld), Ruling::Pass);
assert_eq!(at("box2_thing", Effect::Opaque), Ruling::Hold);
assert_eq!(Ruling::Pass.for_the_operator(), Ruling::Pass);
assert_eq!(Ruling::Hold.for_the_operator(), Ruling::Hold);
}
#[test]
fn an_operators_own_refusal_of_a_routed_call_is_not_turned_back_into_a_park() {
let answers = Answers::fold(&[row(&[YOG_CONTROL, "answer", "toolu_9", "refuse"])]);
assert_eq!(
ruling(
&answers,
&call("toolu_9", "box2_shell", "amber"),
"w",
Effect::Destructive
)
.ruling,
Ruling::Refuse
);
}
#[test]
fn every_other_ops_row_folds_to_nothing() {
let answers = Answers::fold(&[
row(&["bl", "claim", "bl-1a2b", "--as", "amber"]),
row(&[YOG_CONTROL, "answer", "toolu_1", "maybe"]),
row(&[YOG_CONTROL, "answer", "toolu_1", "pass", "everywhere"]),
row(&[YOG_CONTROL, "answer", "toolu_1", "maybe", "call"]),
row(&[YOG_CONTROL, "answer", "amber", "pass", "conversation"]),
row(&[YOG_CONTROL, "floor", "amber", "sideways"]),
row(&[YOG_CONTROL, "answer"]),
row(&[]),
]);
assert_eq!(answers, Answers::default());
}
mod standing;