From d93785ae8309609f0d91af9451597ecb6f77be98 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Mon, 2 Mar 2026 23:24:39 -0500 Subject: [PATCH] Simplify config loading: fix TOCTOU, eager init, remove dead code - Rust: replace exists() check with direct read + NotFound handling - TS: load config eagerly at module init instead of lazy per-request - TS: remove unused resetAppConfigCache() export Co-Authored-By: Claude Opus 4.6 --- apps/arc-web/app/lib/config.server.ts | 18 +++++++----------- crates/arc-api/src/app_config.rs | 9 ++++----- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/apps/arc-web/app/lib/config.server.ts b/apps/arc-web/app/lib/config.server.ts index 9287d7143..3c5fb657d 100644 --- a/apps/arc-web/app/lib/config.server.ts +++ b/apps/arc-web/app/lib/config.server.ts @@ -28,11 +28,7 @@ const API_DEFAULTS: ApiConfig = { authentication_strategy: "jwt", }; -let cached: AppConfig | null = null; - -export function getAppConfig(): AppConfig { - if (cached) return cached; - +function loadAppConfig(): AppConfig { const configPath = join(homedir(), ".arc", "arc.toml"); let raw: Record = {}; @@ -45,15 +41,15 @@ export function getAppConfig(): AppConfig { const rawAuth = (raw.auth ?? {}) as Partial; const rawApi = (raw.api ?? {}) as Partial; - cached = { + return { auth: { ...AUTH_DEFAULTS, ...rawAuth }, api: { ...API_DEFAULTS, ...rawApi }, }; - - return cached; } -/** Reset cached config (for testing). */ -export function resetAppConfigCache(): void { - cached = null; +/** Loaded once at module init; restart the server to pick up changes. */ +const appConfig: AppConfig = loadAppConfig(); + +export function getAppConfig(): AppConfig { + return appConfig; } diff --git a/crates/arc-api/src/app_config.rs b/crates/arc-api/src/app_config.rs index f1d800b58..4cd1b2b69 100644 --- a/crates/arc-api/src/app_config.rs +++ b/crates/arc-api/src/app_config.rs @@ -72,12 +72,11 @@ pub fn load_app_config() -> anyhow::Result { return Ok(AppConfig::default()); }; let path = home.join(".arc").join("arc.toml"); - if !path.exists() { - return Ok(AppConfig::default()); + match std::fs::read_to_string(&path) { + Ok(contents) => Ok(toml::from_str(&contents)?), + Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(AppConfig::default()), + Err(e) => Err(e.into()), } - let contents = std::fs::read_to_string(&path)?; - let config: AppConfig = toml::from_str(&contents)?; - Ok(config) } /// Resolve the data directory: config value > default `~/.arc`.