bascule-workspace/bascule-gateway/src/config.rs
Tyler King b1865a0627 initial: bascule v0.1.0
Bascule shell runtime workspace — governed shell access layer
for Substrate/Guildhouse FFC deployments.

Crates:
- bascule-agent: node agent with SSH server + command filtering
- bascule-core: audit, grant engine, ceremony types, session
- bascule-filter-core: log line filtering (stdio protocol)
- bascule-gateway: OIDC auth, session management, SAT validation
- bascule-node-agent: k8s DaemonSet agent (pod watcher, BPF manager)
- bascule-proto: protobuf definitions
- bascule-shell: governed SSH shell (commands, elevation, REPL)
- bascule-tail: chronicle log tail + fanout
- ceremony-engine: ceremony lifecycle (6 types + request/resolution)

172 tests passing.
Implements SBS-SPEC-0001 shell model.
Reference impl for SPEC-SHELLOPS-0001 Layer 1 (root shell).
2026-03-18 16:40:48 -04:00

149 lines
4.2 KiB
Rust

use serde::Deserialize;
/// Gateway configuration, loaded from environment variables with BASCULE_ prefix.
#[derive(Debug, Deserialize)]
pub struct BasculeConfig {
/// gRPC listen address (default: 0.0.0.0:50052)
#[serde(default = "default_listen_addr")]
pub listen_addr: String,
/// OIDC issuer URL for token validation
#[serde(default = "default_oidc_issuer")]
pub oidc_issuer: String,
/// Expected OIDC audience (client_id)
#[serde(default = "default_oidc_audience")]
pub oidc_audience: String,
/// Default session lifetime in seconds for self-grant ceremonies
#[serde(default = "default_session_lifetime")]
pub session_lifetime_secs: u64,
// --- Database (QM-provisioned bascule_svc credentials) ---
#[serde(default = "default_db_host")]
pub db_host: String,
#[serde(default = "default_db_port")]
pub db_port: u16,
#[serde(default = "default_db_name")]
pub db_name: String,
#[serde(default = "default_db_user")]
pub db_user: String,
#[serde(default)]
pub db_password: String,
// --- OPA sidecar ---
#[serde(default = "default_opa_url")]
pub opa_url: String,
// --- Quartermaster endpoint ---
#[serde(default = "default_qm_endpoint")]
pub qm_endpoint: String,
// --- Accord ---
#[serde(default = "default_accord_path")]
pub accord_path: String,
// --- Audit pipeline ---
#[serde(default = "default_audit_batch_size")]
pub audit_batch_size: usize,
#[serde(default = "default_audit_flush_interval")]
pub audit_flush_interval_secs: u64,
}
fn default_listen_addr() -> String {
"0.0.0.0:50052".to_string()
}
fn default_oidc_issuer() -> String {
"http://localhost:8080/realms/guildhouse".to_string()
}
fn default_oidc_audience() -> String {
"bascule-gateway".to_string()
}
fn default_session_lifetime() -> u64 {
28800 // 8 hours
}
fn default_db_host() -> String {
"localhost".to_string()
}
fn default_db_port() -> u16 {
5432
}
fn default_db_name() -> String {
"telemetry".to_string()
}
fn default_db_user() -> String {
"bascule_svc".to_string()
}
fn default_opa_url() -> String {
"http://localhost:8181".to_string()
}
fn default_qm_endpoint() -> String {
"http://quartermaster.quartermaster.svc.cluster.local:50051".to_string()
}
fn default_accord_path() -> String {
"/accord/accord.yaml".to_string()
}
fn default_audit_batch_size() -> usize {
50
}
fn default_audit_flush_interval() -> u64 {
10
}
impl BasculeConfig {
pub fn from_env() -> anyhow::Result<Self> {
let config = config::Config::builder()
.add_source(
config::Environment::with_prefix("BASCULE")
.separator("__")
.try_parsing(true),
)
.set_default("listen_addr", default_listen_addr())?
.set_default("oidc_issuer", default_oidc_issuer())?
.set_default("oidc_audience", default_oidc_audience())?
.set_default("session_lifetime_secs", default_session_lifetime() as i64)?
.set_default("db_host", default_db_host())?
.set_default("db_port", default_db_port() as i64)?
.set_default("db_name", default_db_name())?
.set_default("db_user", default_db_user())?
.set_default("db_password", "")?
.set_default("opa_url", default_opa_url())?
.set_default("qm_endpoint", default_qm_endpoint())?
.set_default("accord_path", default_accord_path())?
.set_default("audit_batch_size", default_audit_batch_size() as i64)?
.set_default("audit_flush_interval_secs", default_audit_flush_interval() as i64)?
.build()?;
Ok(config.try_deserialize()?)
}
/// HTTP listen address for ceremony approval endpoints.
pub fn http_listen_addr(&self) -> String {
std::env::var("BASCULE__HTTP_LISTEN_ADDR").unwrap_or_else(|_| "0.0.0.0:8443".to_string())
}
/// Build a PostgreSQL connection URL from the individual config fields.
pub fn database_url(&self) -> String {
format!(
"postgresql://{}:{}@{}:{}/{}",
self.db_user, self.db_password, self.db_host, self.db_port, self.db_name
)
}
}