//! The runner seam: an allowed call becomes a `RunSpec` and is handed to a `Runtime`. //! //! A `RunSpec` can only be built here, from a `Decision`, so a runtime never sees a call policy //! did not allow. //! //! ```compile_fail //! let _ = brokerd::runner::RunSpec { //! session: bxcore::SessionId::new("s1").unwrap(), //! call: bxcore::CallId(1), //! tool: brokerd::args::ToolName::Shell, //! arguments: todo!(), //! mounts: Vec::new(), //! egress: None, //! }; //! ``` //! //! ``` //! fn tool_of(spec: &brokerd::runner::RunSpec) -> brokerd::args::ToolName { //! spec.tool() //! } //! ``` use crate::args::{ToolArgs, ToolName}; use crate::policy::{Decision, Label, SessionState}; use bxcore::{CallId, SessionId, ToolResponse}; /// A directory mounted for one call: a path and whether the runtime may write to it. #[derive(Debug, Clone, PartialEq, Eq)] pub struct Mount { pub path: String, pub writable: bool, } /// What one call was turned into before it reached a `Runtime`: the session and call it is, the /// tool, its arguments, the directories mounted and the hosts it may reach. Built only here, from a /// `Decision`. #[derive(Debug)] pub struct RunSpec { session: SessionId, call: CallId, tool: ToolName, arguments: ToolArgs, mounts: Vec, egress: Option>, state: SessionState, } impl RunSpec { pub fn session(&self) -> &SessionId { &self.session } pub fn call(&self) -> CallId { self.call } pub fn tool(&self) -> ToolName { self.tool } pub fn arguments(&self) -> &ToolArgs { &self.arguments } pub fn mounts(&self) -> &[Mount] { &self.mounts } pub fn egress(&self) -> Option<&[String]> { self.egress.as_deref() } /// The session's state when the call was decided. pub fn state(&self) -> SessionState { self.state } } /// A `Runtime`'s answer to one call. Its text reaches the model as a `failed` result labelled /// public and trusted, so a runtime may only put a fixed sentence in it. #[derive(Debug, Clone, PartialEq, Eq)] pub enum RunError { Failed(String), Unavailable(String), } /// What a `Runtime` produced for one call. #[derive(Debug, Clone, PartialEq, Eq)] pub struct RunOutput { pub content: String, pub truncated: bool, } /// Runs one call. `Send + Sync` so one `Runtime` can serve several brokers at once. pub trait Runtime: Send + Sync { fn run(&self, spec: &RunSpec) -> Result; /// `run`, and a label for what came back when the runtime knows one (`memoryd` does: a /// `recall` hit from an untrusted session). The runner keeps the stricter of this and the /// grant's label. Container runtimes know none. fn run_labelled(&self, spec: &RunSpec) -> Result<(RunOutput, Option