brokkr-utils::config
Rust
Brokkr Config Module
This module provides a common configuration framework for our crates.
For detailed configuration documentation, including environment variables, configuration file format, and best practices, see the Configuration Guide.
Variable Naming Convention
Variables in this configuration framework follow these naming conventions:
- Struct fields use snake_case (e.g.,
database,log_level) - Environment variables use SCREAMING_SNAKE_CASE and are prefixed with “BROKKR__” (e.g.,
BROKKR__DATABASE__URL) - Configuration file keys use snake_case (e.g.,
database.url,log.level)
Configuration Overriding
The configuration values are loaded and overridden in the following order (later sources take precedence):
- Default values from the embedded
default.tomlfile - Values from an optional external configuration file (if provided)
- Environment variables
To override a configuration value:
- In a configuration file: Use the appropriate key (e.g.,
database.url = "new_value") - Using environment variables: Set the variable with the “BROKKR__” prefix and “__” as separators
(e.g.,
BROKKR__DATABASE__URL=new_value)
Available Environment Variables
The following environment variables can be used to configure Brokkr:
-
BROKKR__DATABASE__URL: Sets the database connection URL Default: “postgres://brokkr:brokkr@localhost:5433/brokkr” -
BROKKR__DATABASE__SCHEMA: Sets the PostgreSQL schema for multi-tenant isolation Default: None (uses public schema) Example: “tenant_acme” -
BROKKR__LOG__LEVEL: Sets the log level for the application Default: “debug” Possible values: “trace”, “debug”, “info”, “warn”, “error” -
BROKKR__PAK__PREFIX: Sets the prefix for PAKs (Prefixed API Keys) Default: “brokkr” -
BROKKR__PAK__RNG: Sets the random number generator type for PAK generation Default: “osrng” -
BROKKR__PAK__DIGEST: Sets the digest algorithm for PAK generation Default: 8 -
BROKKR__PAK__SHORT_TOKEN_LENGTH: Sets the length of short PAK tokens Default: 8 -
BROKKR__PAK__LONG_TOKEN_LENGTH: Sets the length of long PAK tokens Default: 24 -
BROKKR__PAK__SHORT_TOKEN_PREFIX: Sets the prefix for short PAK tokens Default: “BR” -
BROKKR__BROKER__AUTH_CACHE_TTL_SECONDS: TTL for cached PAK auth results in seconds Default: 60 (set to 0 to disable caching)
Structs
Section titled “Structs”struct Settings
Section titled “struct Settings”pub
Derives: Debug, Deserialize, Clone
Represents the main settings structure for the application
Fields
Section titled “Fields”| Name | Type | Description |
|---|---|---|
database |
Database |
Database configuration |
log |
Log |
Logging configuration |
pak |
PAK |
PAK configuration |
agent |
Agent |
Agent configuration |
broker |
Broker |
Broker configuration |
cors |
Cors |
CORS configuration |
telemetry |
Telemetry |
Telemetry configuration |
Methods
Section titled “Methods”pub
fn new(file: Option<String>) -> Result<Self, ConfigError>Creates a new Settings instance
Parameters:
| Name | Type | Description |
|---|---|---|
file |
Option<String> |
An optional path to a configuration file |
Returns:
Returns a Result containing the Settings instance or a ConfigError
Source
pub fn new(file: Option<String>) -> Result<Self, ConfigError> { // Start with default settings from the embedded TOML file let mut s = Config::builder() .add_source(File::from_str(DEFAULT_SETTINGS, config::FileFormat::Toml));
// If a configuration file is provided, add it as a source s = match file { Some(x) => s.add_source(File::with_name(x.as_str())), None => s, };
// Add environment variables as a source, prefixed with "BROKKR" and using "__" as a separator s = s.add_source(Environment::with_prefix("BROKKR").separator("__"));
// Build the configuration let settings = s.build().unwrap();
// Deserialize the configuration into a Settings instance settings.try_deserialize() }struct Cors
Section titled “struct Cors”pub
Derives: Debug, Deserialize, Clone
Represents the CORS configuration
Fields
Section titled “Fields”| Name | Type | Description |
|---|---|---|
allowed_origins |
Vec<String> |
Allowed origins for CORS requests Use “*” to allow all origins (not recommended for production) Can be set as comma-separated string via env var: “origin1,origin2” |
allowed_methods |
Vec<String> |
Allowed HTTP methods Can be set as comma-separated string via env var: “GET,POST,PUT” |
allowed_headers |
Vec<String> |
Allowed HTTP headers Can be set as comma-separated string via env var: “Authorization,Content-Type” |
max_age_seconds |
u64 |
Max age for preflight cache in seconds |
struct Broker
Section titled “struct Broker”pub
Derives: Debug, Deserialize, Clone
Fields
Section titled “Fields”| Name | Type | Description |
|---|---|---|
pak_hash |
Option<String> |
PAK Hash |
diagnostic_cleanup_interval_seconds |
Option<u64> |
Interval for diagnostic cleanup task in seconds (default: 900 = 15 minutes) |
diagnostic_max_age_hours |
Option<i64> |
Maximum age for completed/expired diagnostics before deletion in hours (default: 1) |
webhook_encryption_key |
Option<String> |
Webhook encryption key (hex-encoded, 32 bytes for AES-256) If not provided, a random key will be generated on startup (not recommended for production) |
webhook_delivery_interval_seconds |
Option<u64> |
Webhook delivery worker interval in seconds (default: 5) |
webhook_delivery_batch_size |
Option<i64> |
Webhook delivery batch size (default: 50) |
webhook_cleanup_retention_days |
Option<i64> |
Webhook delivery cleanup retention in days (default: 7) |
audit_log_retention_days |
Option<i64> |
Audit log retention in days (default: 90) |
auth_cache_ttl_seconds |
Option<u64> |
Auth cache TTL in seconds (default: 60). Set to 0 to disable caching. |
agent_events_retention_days |
Option<i64> |
Agent-events retention in days (default: 30). Events older than this are hard-deleted by the eviction worker. Leaving this unset applies the 30-day default; set it explicitly to 0 to DISABLE eviction and retain all agent events indefinitely. |
struct Agent
Section titled “struct Agent”pub
Derives: Debug, Deserialize, Clone
Represents the agent configuration
Fields
Section titled “Fields”| Name | Type | Description |
|---|---|---|
broker_url |
String |
Broker URL |
polling_interval |
u64 |
Polling interval in seconds |
kubeconfig_path |
Option<String> |
Kubeconfig path |
max_retries |
u32 |
Max number of retries |
pak |
String |
PAK |
agent_name |
String |
Agent name |
cluster_name |
String |
Cluster name |
health_port |
Option<u16> |
Health check HTTP server port |
deployment_health_enabled |
Option<bool> |
Whether deployment health checking is enabled |
deployment_health_interval |
Option<u64> |
Interval for deployment health checks in seconds |
ws_force_rest |
bool |
Force the agent to use REST polling only, never opening the internal WebSocket channel. Defaults to false: WS is opt-out per ADR-0008. Set this for restricted environments (no WS through ingress) or for debugging the REST fallback path in isolation. |
ws_url |
Option<String> |
Optional override for the internal WS upgrade URL. When unset (default), the agent derives the WS URL from broker_url via ws_url_from_broker_url — http→ws, https→wss, append /internal/ws/agent. This is the right behavior for nearly every deployment.Set this when WS traffic flows through a different ingress / proxy than REST: e.g. a sticky-session-capable WS-aware load balancer in front of the broker, while REST goes direct, or — in tests — a toxiproxy sidecar that can sever WS in isolation. Must be a full ws://host:port/path or wss://... URL. |
kube_event_uid_cache_cap |
Option<usize> |
Max entries in the kube-events UID→ownership LRU cache (WS-07). The cache turns the per-Event annotation lookup into an O(1) hit for already-seen objects; the bound stops unmanaged-object churn from growing it without limit. When unset, defaults to 10_000 (sized for ~10k managed pods). Bump for larger clusters; the trade-off is memory vs. how often an evicted entry forces a fresh dynamic-API lookup. |
watch_namespace |
Option<String> |
Restrict the agent’s cluster-wide watchers and health discovery to a single namespace (for namespace-scoped RBAC deployments). When unset the agent watches cluster-wide. The Helm chart sets this from the downward API when rbac.clusterWide: false. |
generator_ids |
Option<String> |
Generator scopes this agent serves, as a comma-separated list of generator UUIDs. On startup the agent self-registers with each so the broker only targets it with stacks owned by these generators (ADR-0009 / BROKKR-I-0030). Resolvable via BROKKR__AGENT__GENERATOR_IDS or a config file. When unset, the agent serves system/fleet scope only — the broker auto-registers every agent with the system generator regardless. A --generator-ids CLI flag overrides this; the legacy bare BROKKR_GENERATOR_IDS env var is still honored (deprecated) as a fallback. |
struct Database
Section titled “struct Database”pub
Derives: Debug, Deserialize, Clone
Represents the database configuration
Fields
Section titled “Fields”| Name | Type | Description |
|---|---|---|
url |
String |
Database connection URL |
schema |
Option<String> |
Optional schema name for multi-tenant isolation |
struct Log
Section titled “struct Log”pub
Derives: Debug, Deserialize, Clone
Represents the logging configuration
Fields
Section titled “Fields”| Name | Type | Description |
|---|---|---|
level |
String |
Log level (e.g., “info”, “debug”, “warn”, “error”) |
format |
String |
Log format: “text” for human-readable, “json” for structured JSON |
struct Telemetry
Section titled “struct Telemetry”pub
Derives: Debug, Deserialize, Clone
Represents the telemetry (OpenTelemetry) configuration with hierarchical overrides
Fields
Section titled “Fields”| Name | Type | Description |
|---|---|---|
enabled |
bool |
Whether telemetry is enabled (base default) |
otlp_endpoint |
String |
OTLP endpoint for trace export (gRPC) |
service_name |
String |
Service name for traces |
sampling_rate |
f64 |
Sampling rate (0.0 to 1.0) |
broker |
TelemetryOverride |
Broker-specific overrides |
agent |
TelemetryOverride |
Agent-specific overrides |
Methods
Section titled “Methods”for_broker
Section titled “for_broker”pub
fn for_broker(&self) -> ResolvedTelemetryGet resolved telemetry config for broker (base merged with broker overrides)
Source
pub fn for_broker(&self) -> ResolvedTelemetry { ResolvedTelemetry { enabled: self.broker.enabled.unwrap_or(self.enabled), otlp_endpoint: self .broker .otlp_endpoint .clone() .unwrap_or_else(|| self.otlp_endpoint.clone()), service_name: self .broker .service_name .clone() .unwrap_or_else(|| self.service_name.clone()), sampling_rate: self.broker.sampling_rate.unwrap_or(self.sampling_rate), } }for_agent
Section titled “for_agent”pub
fn for_agent(&self) -> ResolvedTelemetryGet resolved telemetry config for agent (base merged with agent overrides)
Source
pub fn for_agent(&self) -> ResolvedTelemetry { ResolvedTelemetry { enabled: self.agent.enabled.unwrap_or(self.enabled), otlp_endpoint: self .agent .otlp_endpoint .clone() .unwrap_or_else(|| self.otlp_endpoint.clone()), service_name: self .agent .service_name .clone() .unwrap_or_else(|| self.service_name.clone()), sampling_rate: self.agent.sampling_rate.unwrap_or(self.sampling_rate), } }struct TelemetryOverride
Section titled “struct TelemetryOverride”pub
Derives: Debug, Deserialize, Clone, Default
Component-specific telemetry overrides (all fields optional)
Fields
Section titled “Fields”| Name | Type | Description |
|---|---|---|
enabled |
Option<bool> |
Override enabled flag |
otlp_endpoint |
Option<String> |
Override OTLP endpoint |
service_name |
Option<String> |
Override service name |
sampling_rate |
Option<f64> |
Override sampling rate |
struct ResolvedTelemetry
Section titled “struct ResolvedTelemetry”pub
Derives: Debug, Clone
Resolved telemetry configuration after merging base with overrides
Fields
Section titled “Fields”| Name | Type | Description |
|---|---|---|
enabled |
bool |
|
otlp_endpoint |
String |
|
service_name |
String |
|
sampling_rate |
f64 |
struct PAK
Section titled “struct PAK”pub
Derives: Debug, Deserialize, Clone
Represents the PAK configuration
Fields
Section titled “Fields”| Name | Type | Description |
|---|---|---|
prefix |
Option<String> |
PAK prefix |
digest |
Option<String> |
Digest algorithm for PAK |
rng |
Option<String> |
RNG type for PAK |
short_token_length |
Option<usize> |
Short token length for PAK |
short_token_length_str |
Option<String> |
Short token length as a string |
short_token_prefix |
Option<String> |
Prefix for short tokens |
long_token_length |
Option<usize> |
Long token length for PAK |
long_token_length_str |
Option<String> |
Long token length as a string |
Methods
Section titled “Methods”short_length_as_str
Section titled “short_length_as_str”pub
fn short_length_as_str(&mut self)Convert short token length to string
Source
pub fn short_length_as_str(&mut self) { self.short_token_length_str = self.short_token_length.map(|v| v.to_string()); }long_length_as_str
Section titled “long_length_as_str”pub
fn long_length_as_str(&mut self)Convert long token length to string
Source
pub fn long_length_as_str(&mut self) { self.long_token_length_str = self.long_token_length.map(|v| v.to_string()); }struct DynamicConfig
Section titled “struct DynamicConfig”pub
Derives: Debug, Clone
Dynamic configuration values that can be hot-reloaded at runtime.
These settings can be updated without restarting the application. Changes are applied atomically via the RwLock in ReloadableConfig.
Fields
Section titled “Fields”| Name | Type | Description |
|---|---|---|
log_level |
String |
Log level (e.g., “info”, “debug”, “warn”, “error”) |
diagnostic_cleanup_interval_seconds |
u64 |
Interval for diagnostic cleanup task in seconds |
diagnostic_max_age_hours |
i64 |
Maximum age for completed/expired diagnostics before deletion in hours |
webhook_delivery_interval_seconds |
u64 |
Webhook delivery worker interval in seconds |
webhook_delivery_batch_size |
i64 |
Webhook delivery batch size |
webhook_cleanup_retention_days |
i64 |
Webhook delivery cleanup retention in days |
cors_allowed_origins |
Vec<String> |
Allowed origins for CORS requests |
cors_max_age_seconds |
u64 |
Max age for CORS preflight cache in seconds |
Methods
Section titled “Methods”from_settings
Section titled “from_settings”pub
fn from_settings(settings: &Settings) -> SelfCreate DynamicConfig from Settings
Source
pub fn from_settings(settings: &Settings) -> Self { Self { log_level: settings.log.level.clone(), diagnostic_cleanup_interval_seconds: settings .broker .diagnostic_cleanup_interval_seconds .unwrap_or(900), diagnostic_max_age_hours: settings.broker.diagnostic_max_age_hours.unwrap_or(1), webhook_delivery_interval_seconds: settings .broker .webhook_delivery_interval_seconds .unwrap_or(5), webhook_delivery_batch_size: settings.broker.webhook_delivery_batch_size.unwrap_or(50), webhook_cleanup_retention_days: settings .broker .webhook_cleanup_retention_days .unwrap_or(7), cors_allowed_origins: settings.cors.allowed_origins.clone(), cors_max_age_seconds: settings.cors.max_age_seconds, } }struct ConfigChange
Section titled “struct ConfigChange”pub
Derives: Debug, Clone
Represents a configuration change detected during reload
Fields
Section titled “Fields”| Name | Type | Description |
|---|---|---|
key |
String |
The configuration key that changed |
old_value |
String |
The old value (as string for display) |
new_value |
String |
The new value (as string for display) |
struct ReloadableConfig
Section titled “struct ReloadableConfig”pub
Derives: Clone
Configuration wrapper that separates static (restart-required) settings from dynamic (hot-reloadable) settings.
Static settings are immutable after creation and require an application
restart to change. Dynamic settings can be updated at runtime via the
reload() method.
Examples:
use brokkr_utils::config::ReloadableConfig;
let config = ReloadableConfig::new(None)?;
// Read dynamic config (thread-safe)let log_level = config.log_level();
// Reload config from sourceslet changes = config.reload()?;for change in changes { println!("Changed {}: {} -> {}", change.key, change.old_value, change.new_value);}Methods
Section titled “Methods”pub
fn new(file: Option<String>) -> Result<Self, ConfigError>Creates a new ReloadableConfig instance
Parameters:
| Name | Type | Description |
|---|---|---|
file |
Option<String> |
An optional path to a configuration file |
Returns:
Returns a Result containing the ReloadableConfig instance or a ConfigError
Source
pub fn new(file: Option<String>) -> Result<Self, ConfigError> { let settings = Settings::new(file.clone())?; let dynamic = DynamicConfig::from_settings(&settings);
Ok(Self { static_config: settings, dynamic: Arc::new(RwLock::new(dynamic)), config_file: file, }) }from_settings
Section titled “from_settings”pub
fn from_settings( settings: Settings, config_file: Option<String>,) -> SelfCreates a ReloadableConfig from an existing Settings instance
Parameters:
| Name | Type | Description |
|---|---|---|
settings |
Settings |
The Settings instance to wrap |
config_file |
Option<String> |
An optional path to the config file for future reloads |
Returns:
Returns a ReloadableConfig instance
Source
pub fn from_settings(settings: Settings, config_file: Option<String>) -> Self { let dynamic = DynamicConfig::from_settings(&settings);
Self { static_config: settings, dynamic: Arc::new(RwLock::new(dynamic)), config_file, } }static_config
Section titled “static_config”pub
fn static_config(&self) -> &SettingsGet a reference to the static (immutable) settings
These settings require an application restart to change.
Source
pub fn static_config(&self) -> &Settings { &self.static_config }reload
Section titled “reload”pub
fn reload(&self) -> Result<Vec<ConfigChange>, ConfigError>Reload dynamic configuration from sources (file + environment)
Returns a list of configuration changes that were applied. Thread-safe: blocks writers during reload.
Source
pub fn reload(&self) -> Result<Vec<ConfigChange>, ConfigError> { // Load fresh settings from sources let new_settings = Settings::new(self.config_file.clone())?; let new_dynamic = DynamicConfig::from_settings(&new_settings);
// Acquire write lock and compute changes let mut dynamic = self .dynamic .write() .map_err(|e| ConfigError::Message(format!("Failed to acquire write lock: {}", e)))?;
let mut changes = Vec::new();
// Check each field for changes if dynamic.log_level != new_dynamic.log_level { changes.push(ConfigChange { key: "log.level".to_string(), old_value: dynamic.log_level.clone(), new_value: new_dynamic.log_level.clone(), }); } if dynamic.diagnostic_cleanup_interval_seconds != new_dynamic.diagnostic_cleanup_interval_seconds { changes.push(ConfigChange { key: "broker.diagnostic_cleanup_interval_seconds".to_string(), old_value: dynamic.diagnostic_cleanup_interval_seconds.to_string(), new_value: new_dynamic.diagnostic_cleanup_interval_seconds.to_string(), }); } if dynamic.diagnostic_max_age_hours != new_dynamic.diagnostic_max_age_hours { changes.push(ConfigChange { key: "broker.diagnostic_max_age_hours".to_string(), old_value: dynamic.diagnostic_max_age_hours.to_string(), new_value: new_dynamic.diagnostic_max_age_hours.to_string(), }); } if dynamic.webhook_delivery_interval_seconds != new_dynamic.webhook_delivery_interval_seconds { changes.push(ConfigChange { key: "broker.webhook_delivery_interval_seconds".to_string(), old_value: dynamic.webhook_delivery_interval_seconds.to_string(), new_value: new_dynamic.webhook_delivery_interval_seconds.to_string(), }); } if dynamic.webhook_delivery_batch_size != new_dynamic.webhook_delivery_batch_size { changes.push(ConfigChange { key: "broker.webhook_delivery_batch_size".to_string(), old_value: dynamic.webhook_delivery_batch_size.to_string(), new_value: new_dynamic.webhook_delivery_batch_size.to_string(), }); } if dynamic.webhook_cleanup_retention_days != new_dynamic.webhook_cleanup_retention_days { changes.push(ConfigChange { key: "broker.webhook_cleanup_retention_days".to_string(), old_value: dynamic.webhook_cleanup_retention_days.to_string(), new_value: new_dynamic.webhook_cleanup_retention_days.to_string(), }); } if dynamic.cors_allowed_origins != new_dynamic.cors_allowed_origins { changes.push(ConfigChange { key: "cors.allowed_origins".to_string(), old_value: format!("{:?}", dynamic.cors_allowed_origins), new_value: format!("{:?}", new_dynamic.cors_allowed_origins), }); } if dynamic.cors_max_age_seconds != new_dynamic.cors_max_age_seconds { changes.push(ConfigChange { key: "cors.max_age_seconds".to_string(), old_value: dynamic.cors_max_age_seconds.to_string(), new_value: new_dynamic.cors_max_age_seconds.to_string(), }); }
// Apply the new configuration let log_level_changed = dynamic.log_level != new_dynamic.log_level; let new_log_level = new_dynamic.log_level.clone(); *dynamic = new_dynamic; drop(dynamic);
// Push the log level into the logger (BROKKR-T-0292). // // Applied here rather than by callers so that *every* reload path gets // it — the ConfigMap watcher and `POST /admin/config/reload` alike. // Before this, `reload()` recomputed the level, reported it as a change, // and left the logger untouched: `update_log_level` existed and had no // caller outside its own tests, so the level was restart-only in // practice while being advertised as hot-reloadable. // // The lock is released first: `update_log_level` only touches an atomic // and `log::set_max_level`, but holding a config write lock across a // call into another module is how deadlocks get introduced later. if log_level_changed { if let Err(e) = crate::logging::update_log_level(&new_log_level) { // A bad level in config should not abort a reload that also // carried good changes; the level simply stays where it was. eprintln!("failed to apply reloaded log level '{new_log_level}': {e}"); } // The broker logs through `tracing`, and `update_log_level` above // only moves the `log` crate's level. Change the `tracing` filter // too, or the reload is reported and the output does not change. match crate::telemetry::set_log_level(&new_log_level) { Ok(true) => {} Ok(false) => eprintln!( "reloaded log level '{new_log_level}' not applied to tracing: \ RUST_LOG set the filter at startup, or tracing is not initialized" ), Err(e) => { eprintln!("failed to apply reloaded log level '{new_log_level}': {e}") } } }
Ok(changes) }log_level
Section titled “log_level”pub
fn log_level(&self) -> StringGet current log level
Source
pub fn log_level(&self) -> String { self.dynamic .read() .map(|d| d.log_level.clone()) .unwrap_or_else(|_| "info".to_string()) }diagnostic_cleanup_interval_seconds
Section titled “diagnostic_cleanup_interval_seconds”pub
fn diagnostic_cleanup_interval_seconds(&self) -> u64Get diagnostic cleanup interval in seconds
Source
pub fn diagnostic_cleanup_interval_seconds(&self) -> u64 { self.dynamic .read() .map(|d| d.diagnostic_cleanup_interval_seconds) .unwrap_or(900) }diagnostic_max_age_hours
Section titled “diagnostic_max_age_hours”pub
fn diagnostic_max_age_hours(&self) -> i64Get diagnostic max age in hours
Source
pub fn diagnostic_max_age_hours(&self) -> i64 { self.dynamic .read() .map(|d| d.diagnostic_max_age_hours) .unwrap_or(1) }webhook_delivery_interval_seconds
Section titled “webhook_delivery_interval_seconds”pub
fn webhook_delivery_interval_seconds(&self) -> u64Get webhook delivery interval in seconds
Source
pub fn webhook_delivery_interval_seconds(&self) -> u64 { self.dynamic .read() .map(|d| d.webhook_delivery_interval_seconds) .unwrap_or(5) }webhook_delivery_batch_size
Section titled “webhook_delivery_batch_size”pub
fn webhook_delivery_batch_size(&self) -> i64Get webhook delivery batch size
Source
pub fn webhook_delivery_batch_size(&self) -> i64 { self.dynamic .read() .map(|d| d.webhook_delivery_batch_size) .unwrap_or(50) }webhook_cleanup_retention_days
Section titled “webhook_cleanup_retention_days”pub
fn webhook_cleanup_retention_days(&self) -> i64Get webhook cleanup retention in days
Source
pub fn webhook_cleanup_retention_days(&self) -> i64 { self.dynamic .read() .map(|d| d.webhook_cleanup_retention_days) .unwrap_or(7) }cors_allowed_origins
Section titled “cors_allowed_origins”pub
fn cors_allowed_origins(&self) -> Vec<String>Get CORS allowed origins
Source
pub fn cors_allowed_origins(&self) -> Vec<String> { self.dynamic .read() .map(|d| d.cors_allowed_origins.clone()) .unwrap_or_else(|_| vec!["*".to_string()]) }cors_max_age_seconds
Section titled “cors_max_age_seconds”pub
fn cors_max_age_seconds(&self) -> u64Get CORS max age in seconds
Source
pub fn cors_max_age_seconds(&self) -> u64 { self.dynamic .read() .map(|d| d.cors_max_age_seconds) .unwrap_or(3600) }dynamic_snapshot
Section titled “dynamic_snapshot”pub
fn dynamic_snapshot(&self) -> Option<DynamicConfig>Get a snapshot of all dynamic config values
Source
pub fn dynamic_snapshot(&self) -> Option<DynamicConfig> { self.dynamic.read().ok().map(|d| d.clone()) }Constants
Section titled “Constants”| Name | Type | Value | Description |
|---|---|---|---|
DEFAULT_ADMIN_PAK_HASH |
&str |
"4c697273df3d764cba950bb5c04368097685f09259f5bd880d892cf1... |
The admin PAK hash shipped in the embedded default.toml.This is a publicly known credential: the raw PAK it hashes is written in a comment directly above it in default.toml, and both are in the public source tree. It exists so the development and test harnesses work with zero configuration; a broker that still has it as its admin credential accepts an admin PAK that anyone can read out of the repository.It lives here, next to the include_str! of the file it mirrors, so the literal and its source can be compared without a runtime config load — and default_admin_pak_hash_constant_matches_default_toml in this module’s test suite fails the build if they ever drift. Consumers must compare against this constant rather than re-deriving the value, so there is exactly one definition of “the shipped default” in the codebase.See brokkr_broker::utils::detect_default_admin_pak_hash for the startup backstop that acts on it (BROKKR-T-0298). |