//! Scripted stand-ins for `brokerd`'s admin socket and for `loopd`, for tests. Do not edit. #![allow(dead_code)] // each test file uses a different part of this module use proto::{ ApprovalList, CallId, DataClass, Envelope, ErrorCode, Message, PROTOCOL_VERSION, PendingApproval, SessionId, Timestamp, TurnDone, TurnEvent, Usage, WireError, read_frame, write_frame, }; use std::os::unix::net::UnixListener; use std::path::PathBuf; use std::sync::atomic::{AtomicU32, Ordering}; use std::sync::{Arc, Mutex}; use std::thread; static NEXT: AtomicU32 = AtomicU32::new(0); /// A socket path in a fresh temporary directory. pub fn temp_socket(name: &str) -> PathBuf { let n = NEXT.fetch_add(1, Ordering::SeqCst); let dir = std::env::temp_dir().join(format!("bxctl-m3a-{}-{n}", std::process::id())); std::fs::create_dir_all(&dir).unwrap(); dir.join(name) } pub fn ts(text: &str) -> Timestamp { Timestamp::parse(text).unwrap() } pub struct FakeBrokerd { pub socket: PathBuf, /// Every request message received, in order. pub requests: Arc>>, } impl FakeBrokerd { pub fn requests(&self) -> Vec { self.requests.lock().unwrap().clone() } } /// Serves `admin.sock`: one request per connection, answered with the frames `answer` returns, /// written exactly as given (so a test can send a wrong id or a frame that is not final). An /// empty list closes the connection without an answer. pub fn fake_brokerd_frames( answer: impl Fn(&Envelope) -> Vec + Send + 'static, ) -> FakeBrokerd { let socket = temp_socket("admin.sock"); let listener = UnixListener::bind(&socket).unwrap(); let requests = Arc::new(Mutex::new(Vec::new())); let seen = Arc::clone(&requests); thread::spawn(move || { for stream in listener.incoming() { let Ok(mut stream) = stream else { continue }; let Ok(request) = read_frame(&mut stream) else { continue; }; seen.lock().unwrap().push(request.msg.clone()); for frame in answer(&request) { if write_frame(&mut stream, &frame).is_err() { break; // the client went away; the next connection is still served } } } }); FakeBrokerd { socket, requests } } /// The usual case: one final frame with the request's id. pub fn fake_brokerd(answer: impl Fn(&Message) -> Message + Send + 'static) -> FakeBrokerd { fake_brokerd_frames(move |request| { vec![Envelope { v: PROTOCOL_VERSION, id: request.id, r#final: true, msg: answer(&request.msg), }] }) } pub fn wire_error(code: ErrorCode, detail: &str) -> Message { Message::Error(WireError { code, detail: detail.to_string(), }) } /// A pending approval created at 12:00:00 that expires at 12:15:00 on 2026-09-18. pub fn pending(approval: u64, tool: &str, arguments: &str) -> PendingApproval { PendingApproval { approval, session: SessionId::new("chat-1758196800-123456789").unwrap(), call: CallId(7), tool: tool.to_string(), arguments: arguments.to_string(), grant: "shell-scratch".to_string(), taint: DataClass::Private, created: ts("2026-09-18T12:00:00.000Z"), expires: ts("2026-09-18T12:15:00.000Z"), } } /// A `brokerd` with these approvals pending. `approve` is answered with `outcome`, `refuse` with /// `ok`; both answer `no_such_approval` for an id that is not in the list. pub fn brokerd_with(items: Vec, outcome: proto::DecisionRecord) -> FakeBrokerd { fake_brokerd(move |msg| { let known = |id: u64| items.iter().any(|item| item.approval == id); match msg { Message::Approvals(_) => Message::ApprovalList(ApprovalList { items: items.clone(), }), Message::Approve(a) if known(a.approval) => { Message::ApproveResult(proto::ApproveResult { outcome: outcome.clone(), }) } Message::Refuse(r) if known(r.approval) => Message::Ok(proto::Empty {}), Message::Approve(_) | Message::Refuse(_) => { wire_error(ErrorCode::NoSuchApproval, "no such approval") } _ => wire_error(ErrorCode::BadMessage, "not an admin request"), } }) } pub struct FakeLoopd { pub socket: PathBuf, /// The content of every turn received, in order. pub turns: Arc>>, } pub fn usage() -> Usage { Usage { cache_n: 10, prompt_n: 5, predicted_n: 7, reasoning_tokens: 3, thinking_capped: false, } } /// Serves `loop.sock`: every turn gets the same events, then `turn_done` with `answer`. It does /// not wait for an approval to be answered: `bxctl` deals with each event before it reads the /// next frame, so the order of what it does is fixed all the same. pub fn fake_loopd(events: Vec, answer: &str) -> FakeLoopd { let socket = temp_socket("loop.sock"); let listener = UnixListener::bind(&socket).unwrap(); let turns = Arc::new(Mutex::new(Vec::new())); let seen = Arc::clone(&turns); let answer = answer.to_string(); thread::spawn(move || { for stream in listener.incoming() { let Ok(mut stream) = stream else { continue }; let Ok(request) = read_frame(&mut stream) else { continue; }; let Message::Turn(turn) = request.msg else { continue; }; seen.lock().unwrap().push(turn.content); let mut frames: Vec<(bool, Message)> = events .iter() .map(|e| (false, Message::TurnEvent(e.clone()))) .collect(); frames.push(( true, Message::TurnDone(TurnDone { content: answer.clone(), usage: usage(), }), )); for (last, msg) in frames { let frame = Envelope { v: PROTOCOL_VERSION, id: request.id, r#final: last, msg, }; if write_frame(&mut stream, &frame).is_err() { break; } } } }); FakeLoopd { socket, turns } }