From 9fb101282f728e5135cb484e4e7557570f0846ef Mon Sep 17 00:00:00 2001 From: Octopus Date: Thu, 23 Apr 2026 04:37:22 +0800 Subject: [PATCH] fix: --config flag now fully overrides ~/.strix/cli-config.json (#457) * fix: --config flag now fully overrides ~/.strix/cli-config.json (fixes #377) Previously, env vars applied from the default config at module import time were not cleared when --config was later processed, causing settings from ~/.strix/cli-config.json to leak into runs that specified a custom config. Track which vars were applied by the initial default-config load in Config._applied_from_default. In apply_config_override, clear those vars before applying the custom config so only the custom file's settings take effect. * Add config override regression test * Make config override test setup explicit --------- Co-authored-by: octo-patch Co-authored-by: bearsyankees --- strix/config/config.py | 11 +++++++++- strix/interface/main.py | 7 +++++++ tests/config/test_config_override.py | 31 ++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 tests/config/test_config_override.py diff --git a/strix/config/config.py b/strix/config/config.py index 782101d..255df7c 100644 --- a/strix/config/config.py +++ b/strix/config/config.py @@ -2,7 +2,7 @@ import contextlib import json import os from pathlib import Path -from typing import Any +from typing import Any, ClassVar STRIX_API_BASE = "https://models.strix.ai/api/v1" @@ -56,6 +56,10 @@ class Config: # Config file override (set via --config CLI arg) _config_file_override: Path | None = None + # Tracks env vars set by the initial default-config load so they can be + # cleared when a --config override is later applied (avoids leakage). + _applied_from_default: ClassVar[dict[str, str]] = {} + @classmethod def _tracked_names(cls) -> list[str]: return [ @@ -151,6 +155,11 @@ class Config: os.environ[var_name] = var_value applied[var_name] = var_value + # Record what was applied from the default config so it can be cleared + # if a --config override is later provided (prevents leakage). + if cls._config_file_override is None and not force: + cls._applied_from_default = applied + return applied @classmethod diff --git a/strix/interface/main.py b/strix/interface/main.py index 7ac6f13..bc88da6 100644 --- a/strix/interface/main.py +++ b/strix/interface/main.py @@ -6,6 +6,7 @@ Strix Agent Interface import argparse import asyncio import logging +import os import shutil import sys from pathlib import Path @@ -528,6 +529,12 @@ def pull_docker_image() -> None: def apply_config_override(config_path: str) -> None: + # Clear env vars that were automatically applied from the default config file + # so they don't leak into the custom config context. + for var_name in Config._applied_from_default: + os.environ.pop(var_name, None) + Config._applied_from_default = {} + Config._config_file_override = validate_config_file(config_path) apply_saved_config(force=True) diff --git a/tests/config/test_config_override.py b/tests/config/test_config_override.py new file mode 100644 index 0000000..51f6069 --- /dev/null +++ b/tests/config/test_config_override.py @@ -0,0 +1,31 @@ +import json +import os + +from strix.config.config import Config, apply_saved_config + + +def test_apply_config_override_clears_default_only_vars(monkeypatch, tmp_path) -> None: + from strix.interface.main import apply_config_override + + default_cfg = tmp_path / "cli-config.json" + default_cfg.write_text( + json.dumps({"env": {"LLM_API_BASE": "https://default.api", "STRIX_LLM": "default-model"}}), + encoding="utf-8", + ) + custom_cfg = tmp_path / "custom.json" + custom_cfg.write_text(json.dumps({"env": {"STRIX_LLM": "custom-model"}}), encoding="utf-8") + + monkeypatch.setattr(Config, "_config_file_override", None) + monkeypatch.setattr(Config, "_applied_from_default", {}) + monkeypatch.setattr(Config, "config_dir", classmethod(lambda cls: tmp_path)) + for var_name in Config._llm_env_vars(): + monkeypatch.delenv(var_name, raising=False) + + apply_saved_config() + + assert os.environ.get("LLM_API_BASE") == "https://default.api" + + apply_config_override(str(custom_cfg)) + + assert os.environ.get("STRIX_LLM") == "custom-model" + assert "LLM_API_BASE" not in os.environ