mirror of
https://github.com/outbackdingo/optimclaw.git
synced 2026-08-26 15:40:18 +00:00
fix(security): make unsafe env::set_var calls safe with explicit invariants (#968)
* fix(security): make unsafe env::set_var calls safe with explicit invariants `std::env::set_var` is unsafe in Rust 1.82+ because concurrent calls from multiple threads cause undefined behavior. This commit addresses the two production-code call sites: 1. `bootstrap.rs:load_ironclaw_env()` -- called before the Tokio runtime starts (genuinely single-threaded). Added a `debug_assert!` that verifies no Tokio runtime is active, making the safety invariant machine-checkable rather than relying on a comment. 2. `llm/session.rs:api_key_login()` -- was calling `set_var` mid- execution inside the multi-threaded Tokio runtime (UB risk). Replaced with `set_runtime_env()`, a new thread-safe overlay backed by `OnceLock<Mutex<HashMap>>`. The overlay integrates with the existing `optional_env()` config resolution and a new `env_or_override()` reader function. All call sites that read `NEARAI_API_KEY` via raw `std::env::var()` (wizard.rs, main.rs, doctor.rs) are updated to use the thread-safe `env_or_override()` helper instead, so the value set during interactive login is visible without mutating the process environment. Test code `set_var`/`remove_var` calls (bootstrap tests, config tests, shell tests, oauth tests, wizard tests) are left as-is since they run under `ENV_MUTEX` serialization and are not production paths. Co-Authored-By: Claude Sonnet 4.6 <[email protected]> * fix: address review feedback on thread-safe env overlay PR - Replace debug_assert! with runtime check in bootstrap.rs so release builds skip unsafe set_var when a Tokio runtime is active - Recover from mutex poison in set_runtime_env instead of silently dropping writes (poisoned HashMap is still usable) - Skip empty override values in env_or_override and optional_env for consistency with real env var handling - Fix doc comment on env_or_override (real env checked first, not runtime overrides) - Update api_key_login doc to describe runtime overlay instead of env var mutation [skip-regression-check] Co-Authored-By: Claude Sonnet 4.6 <[email protected]> * fix: use LazyLock::lock() for INJECTED_VARS; use set_runtime_env() in bootstrap fallback - helpers.rs: fix env_or_override() to call INJECTED_VARS.lock() instead of .get() — INJECTED_VARS was changed upstream from OnceLock<HashMap> to LazyLock<Mutex<HashMap>>; calling .get() caused a compile error (E0599: no method named 'get' for LazyLock) - bootstrap.rs: when load_ironclaw_env() is called with an active Tokio runtime, use set_runtime_env("DATABASE_BACKEND", "libsql") instead of silently dropping the write. This ensures DATABASE_BACKEND is always set regardless of thread context (addresses ilblackdragon review item 1). Co-Authored-By: Claude Sonnet 4.6 <[email protected]> --------- Co-authored-by: Gabe Hamilton <[email protected]> Co-authored-by: Claude Sonnet 4.6 <[email protected]>
This commit is contained in:
co-authored by
Gabe Hamilton
Claude Sonnet 4.6
parent
8bbb43da52
commit
a9821ac20f
+6
-5
@@ -1183,9 +1183,9 @@ impl SetupWizard {
|
||||
self.persist_session_to_db().await;
|
||||
|
||||
// If the user chose the API key path, NEARAI_API_KEY is now set
|
||||
// in the environment. Persist it to the encrypted secrets store
|
||||
// so inject_llm_keys_from_secrets() can load it on future runs.
|
||||
if let Ok(api_key) = std::env::var("NEARAI_API_KEY")
|
||||
// in the runtime env overlay. Persist it to the encrypted secrets
|
||||
// store so inject_llm_keys_from_secrets() can load it on future runs.
|
||||
if let Some(api_key) = crate::config::helpers::env_or_override("NEARAI_API_KEY")
|
||||
&& !api_key.is_empty()
|
||||
&& let Ok(ctx) = self.init_secrets_context().await
|
||||
{
|
||||
@@ -2613,8 +2613,9 @@ impl SetupWizard {
|
||||
env_vars.push((base_url_env.clone(), base_url.clone()));
|
||||
}
|
||||
|
||||
// Preserve NEARAI_API_KEY if present (set by API key auth flow)
|
||||
if let Ok(api_key) = std::env::var("NEARAI_API_KEY")
|
||||
// Preserve NEARAI_API_KEY if present (set by API key auth flow
|
||||
// via the thread-safe runtime env overlay).
|
||||
if let Some(api_key) = crate::config::helpers::env_or_override("NEARAI_API_KEY")
|
||||
&& !api_key.is_empty()
|
||||
{
|
||||
env_vars.push(("NEARAI_API_KEY".to_string(), api_key));
|
||||
|
||||
Reference in New Issue
Block a user