mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-10-01 02:04:24 +00:00
The OpenAPI spec adopts the lithos request, response, content part, tool, usage, and cost schemas. The completions endpoint returns the lithos `Response` JSON verbatim and SSE carries lithos `StreamEvent`s verbatim. The models and providers endpoints serve the fabro-types catalog views, and the install and model-test flows probe providers through fabro-llm. The CLI builds its catalog from the operator overlay, drives `fabro exec` through the server gateway adapter, and parses reasoning effort with the shared controls. The web app reads content parts as lithos-tagged objects. The TypeScript client is regenerated. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
89 lines
2.4 KiB
Rust
89 lines
2.4 KiB
Rust
use std::collections::HashMap;
|
|
use std::path::Path;
|
|
|
|
use fabro_config::envfile;
|
|
|
|
#[expect(
|
|
clippy::disallowed_methods,
|
|
reason = "ServerSecrets snapshots process env once at startup by design."
|
|
)]
|
|
pub fn process_env_snapshot() -> HashMap<String, String> {
|
|
std::env::vars().collect()
|
|
}
|
|
|
|
#[derive(Debug, thiserror::Error)]
|
|
pub(crate) enum Error {
|
|
#[error(transparent)]
|
|
Io(#[from] std::io::Error),
|
|
}
|
|
|
|
pub(crate) struct ServerSecrets {
|
|
env_entries: HashMap<String, String>,
|
|
file_entries: HashMap<String, String>,
|
|
}
|
|
|
|
impl ServerSecrets {
|
|
pub(crate) fn load(
|
|
path: impl AsRef<Path>,
|
|
env_entries: HashMap<String, String>,
|
|
) -> Result<Self, Error> {
|
|
Ok(Self {
|
|
env_entries,
|
|
file_entries: envfile::read_env_file(path.as_ref())?,
|
|
})
|
|
}
|
|
|
|
pub(crate) fn get(&self, name: &str) -> Option<String> {
|
|
self.env_entries
|
|
.get(name)
|
|
.cloned()
|
|
.or_else(|| self.file_entries.get(name).cloned())
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Debug for ServerSecrets {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
f.debug_struct("ServerSecrets")
|
|
.field("env_entries", &self.env_entries.keys().collect::<Vec<_>>())
|
|
.field(
|
|
"file_entries",
|
|
&self.file_entries.keys().collect::<Vec<_>>(),
|
|
)
|
|
.finish_non_exhaustive()
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use std::collections::HashMap;
|
|
|
|
use fabro_config::envfile;
|
|
|
|
use super::ServerSecrets;
|
|
|
|
#[test]
|
|
fn bootstrap_server_secrets_snapshot_prefers_env_over_file() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let env_path = dir.path().join("server.env");
|
|
envfile::write_env_file(
|
|
&env_path,
|
|
&HashMap::from([
|
|
("SESSION_SECRET".to_string(), "file-value".to_string()),
|
|
("FABRO_DEV_TOKEN".to_string(), "file-dev-token".to_string()),
|
|
]),
|
|
)
|
|
.unwrap();
|
|
|
|
let secrets = ServerSecrets::load(
|
|
env_path,
|
|
HashMap::from([("SESSION_SECRET".to_string(), "env-value".to_string())]),
|
|
)
|
|
.unwrap();
|
|
|
|
assert_eq!(secrets.get("SESSION_SECRET").as_deref(), Some("env-value"));
|
|
assert_eq!(
|
|
secrets.get("FABRO_DEV_TOKEN").as_deref(),
|
|
Some("file-dev-token")
|
|
);
|
|
}
|
|
}
|