//! An answer from Mattermost records who answered and in which post, approved or refused; the //! table says whether an approval is still pending (M4b spec, section 5). Do not edit. #[path = "support/build.rs"] mod build; #[path = "support/rig.rs"] mod rig; #[path = "support/sink.rs"] mod sink; #[path = "support/tmp.rs"] mod tmp; use brokerd::approvals::Table; use brokerd::ledger::{Answer, Decided, Grants, Ledger}; use brokerd::policy::Ask; use build::{grant, now, read, set}; use proto::{ApprovalAnswer, AuditEvent, CallId, DataClass, Mode, PendingApproval, SessionId}; use rig::Rig; const KYLE: &str = "k0000000000000000000000000"; const POST: &str = "c0000000000000000000000001"; fn asking() -> Grants { Ok(set(vec![grant("n", "read_file", Mode::Ask).paths(&["/n"])])) } fn pending(ledger: &Ledger) -> Ask { match ledger.decide(read("/n/deep/a"), &asking(), now()) { Decided::Ask { ask, seq: 0, .. } => ask, other => panic!("{other:?}"), } } /// The one `Approval` record's (answer, by, post, reason). fn recorded( rig: &Rig, ) -> ( ApprovalAnswer, Option, Option, Option, ) { let events = rig.events(); match &events[1] { AuditEvent::Approval { answer, by, post, reason, .. } => (*answer, by.clone(), post.clone(), reason.clone()), other => panic!("{other:?}"), } } #[test] fn an_approval_from_mattermost_names_the_user_and_the_post() { let rig = Rig::new("post-approve"); let ledger = rig.ledger(); let answer = Answer::Approved { by: Some(KYLE.to_string()), post: Some(POST.to_string()), }; ledger.answer(pending(&ledger), 0, answer, &asking(), now()); assert_eq!( recorded(&rig), ( ApprovalAnswer::Approved, Some(KYLE.to_string()), Some(POST.to_string()), None ) ); } #[test] fn a_refusal_from_mattermost_names_them_and_keeps_the_reason() { let rig = Rig::new("post-refuse"); let ledger = rig.ledger(); let answer = Answer::Refused { by: Some(KYLE.to_string()), post: Some(POST.to_string()), reason: Some("not on a Friday".to_string()), }; ledger.answer(pending(&ledger), 0, answer, &asking(), now()); assert_eq!( recorded(&rig), ( ApprovalAnswer::Refused, Some(KYLE.to_string()), Some(POST.to_string()), Some("not on a Friday".to_string()) ) ); } #[test] fn the_table_says_what_is_pending() { let rig = Rig::new("post-table"); let ledger = rig.ledger(); let table = Table::new(); assert!(!table.contains(0)); let info = PendingApproval { approval: 0, session: SessionId::new("s1").unwrap(), call: CallId(1), tool: "read_file".to_string(), arguments: "{}".to_string(), grant: "n".to_string(), taint: DataClass::Private, created: now(), expires: now(), }; let _verdict = table.insert(info, pending(&ledger)); assert!(table.contains(0) && !table.contains(1)); assert!(table.take(0).is_some()); assert!(!table.contains(0)); }