From 8bbdf5a27af3e8141b60aa1ab032d77bb41d6864 Mon Sep 17 00:00:00 2001 From: Jer Miller Date: Tue, 5 May 2026 05:38:31 -0600 Subject: [PATCH] fix(settings): mirror env var changes to os.environ on http save path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The HTTP /api/config save path wrote provider keys to journal.json but never updated os.environ in the running supervisor — so a key saved via the localhost:5015 wizard validated successfully yet /api/providers and sol call settings providers reported configured:false until restart. Mirrors the cli pattern in apps/settings/call.py:362-394 (set/clear). After this, the wizard is self-sufficient — no service restart required after pasting a key on a fresh install. Regression test asserts os.environ reflects both set and clear in-process through the http endpoint. Refs req_uf5stjw7. Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/settings/routes.py | 5 +++++ tests/test_validate_key.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/apps/settings/routes.py b/apps/settings/routes.py index b1e9d8da6..6bcbfb4ce 100644 --- a/apps/settings/routes.py +++ b/apps/settings/routes.py @@ -229,6 +229,11 @@ def update_config() -> Any: if old_value != new_value: changed_fields[key] = {"old": old_value, "new": new_value} config[section][key] = new_value + if section == "env": + if new_value: + os.environ[key] = new_value + else: + os.environ.pop(key, None) # Hash password before writing to disk if section == "convey" and "password" in data: diff --git a/tests/test_validate_key.py b/tests/test_validate_key.py index 9986292a9..19de7006e 100644 --- a/tests/test_validate_key.py +++ b/tests/test_validate_key.py @@ -4,6 +4,7 @@ from __future__ import annotations import json +import os from unittest.mock import Mock, patch import pytest @@ -309,6 +310,34 @@ def test_update_config_clears_key_validation(settings_client): assert "google" not in saved["providers"]["key_validation"] +def test_update_config_env_mirrors_os_environ(settings_client, monkeypatch): + """The HTTP env-section save path must mirror into os.environ in-process, + matching the CLI pattern (apps/settings/call.py keys_set/keys_clear). + Without this, /api/providers reports `configured: false` until restart.""" + client, _ = settings_client + monkeypatch.delenv("GOOGLE_API_KEY", raising=False) + + with patch( + "think.providers.validate_key", + return_value={"valid": True}, + ): + response = client.put( + "/app/settings/api/config", + json={"section": "env", "data": {"GOOGLE_API_KEY": "live-key"}}, + ) + + assert response.status_code == 200 + assert os.environ.get("GOOGLE_API_KEY") == "live-key" + + response = client.put( + "/app/settings/api/config", + json={"section": "env", "data": {"GOOGLE_API_KEY": ""}}, + ) + + assert response.status_code == 200 + assert "GOOGLE_API_KEY" not in os.environ + + def test_get_providers_includes_key_validation(settings_client): client, journal = settings_client config_path = journal / "config" / "journal.json" -- 2.51.2