//! Keep a process-local vault behind a fixed endpoint at `/run/secrets`. //! Start `secrets.serve` as a detached boot service. Its memory lasts until process exit. use sausage_plugin::{Ctx, Result, listen, rpc, schema}; use std::{cell::RefCell, collections::BTreeMap, rc::Rc}; struct Secrets; #[rpc(endpoints(vault=Vault))] impl Secrets { /// Open the in-memory vault and publish its endpoint. async fn serve(&self) -> Result<()> { listen("/run/secrets", Rc::new(Vault::default())).await } } #[derive(Default)] struct Vault { entries: RefCell>, } /// The name and value of a secret. #[schema] struct PutParams { /// The unique name within this vault. name: String, /// The text to store until process exit. value: String, } /// The name of a secret to read. #[schema] struct GetParams { /// The unique name within this vault. name: String, } #[rpc] impl Vault { /// Store a secret and report its name to the caller. fn put(&self, ctx: &Ctx, p: PutParams) -> Result<()> { ctx.notify("stored", sausage_plugin::serde_json::json!({"name":p.name}))?; self.entries.borrow_mut().insert(p.name, p.value); Ok(()) } /// Read a secret, or return null when its name is absent. fn get(&self, p: GetParams) -> Result> { Ok(self.entries.borrow().get(&p.name).cloned()) } } fn main() { sausage_plugin::run(Secrets) }