feat(settings): add explicit settings dir override for sandboxed runs

Add LORA_MANAGER_SETTINGS_DIR env var and standalone --settings-path to pin
the settings location (settings.json, cache/, wildcards/, backups/, logs/,
stats/) to an arbitrary directory. The override takes precedence over
portable mode and the platform user config dir, and skips legacy migration,
so sandboxed dev/E2E runs no longer need to write settings.json in the repo
root or collide with the real instance.

standalone.py pre-scans argv for --settings-path at import time because the
settings location is resolved before main() parses arguments. SettingsManager
portable-switch migration is a no-op while the directory is pinned.

Update the lora-manager-e2e skill (prefer --settings-path sandboxing;
start_server.py passes it through) and the lora-manager-runtime-context
skill (document precedence; inspect script honors the override).
This commit is contained in:
Will Miao
2026-08-27 00:03:50 +08:00
parent 1d3bcdfe47
commit 574dfbbe55
10 changed files with 383 additions and 30 deletions
+86 -1
View File
@@ -6,7 +6,26 @@ import os
import pytest
from py.utils.settings_paths import _should_use_portable_settings
from py.utils.settings_paths import (
SETTINGS_DIR_ENV,
_should_use_portable_settings,
ensure_settings_file,
get_settings_dir,
get_settings_dir_override,
is_settings_dir_pinned,
set_settings_dir_override,
)
def _redirect_paths(tmp_path, monkeypatch):
"""Pin project root and user config dir resolution to temp paths."""
monkeypatch.setattr(
"py.utils.settings_paths.get_project_root", lambda: str(tmp_path / "repo")
)
monkeypatch.setattr(
"py.utils.settings_paths.user_config_dir",
lambda *args, **kwargs: str(tmp_path / "user_config"),
)
class TestShouldUsePortableSettings:
@@ -54,3 +73,69 @@ class TestShouldUsePortableSettings:
mp.setenv("LORA_MANAGER_PORTABLE", "1")
result = _should_use_portable_settings(str(missing), logging.getLogger())
assert result is True
class TestExplicitSettingsDirOverride:
"""Tests for the LORA_MANAGER_SETTINGS_DIR / --settings-path override."""
def test_env_override_wins_over_portable_and_user_config(self, tmp_path, monkeypatch):
_redirect_paths(tmp_path, monkeypatch)
repo = tmp_path / "repo"
repo.mkdir()
(repo / "settings.json").write_text(
json.dumps({"use_portable_settings": True}), encoding="utf-8"
)
custom_dir = tmp_path / "custom" / "e2e"
monkeypatch.setenv(SETTINGS_DIR_ENV, str(custom_dir))
monkeypatch.delenv("LORA_MANAGER_PORTABLE", raising=False)
assert is_settings_dir_pinned()
target = get_settings_dir(create=True)
assert target == str(custom_dir.resolve())
assert target == os.path.abspath(str(custom_dir))
assert custom_dir.is_dir()
# The override is independent of the effective use_portable flag.
with pytest.MonkeyPatch.context() as mp:
mp.setenv("LORA_MANAGER_PORTABLE", "1")
assert get_settings_dir(create=False) == os.path.abspath(str(custom_dir))
def test_env_override_normalizes_tilde(self, monkeypatch):
monkeypatch.setenv(SETTINGS_DIR_ENV, "~/lm-e2e-settings")
override = get_settings_dir_override()
assert override == os.path.abspath(os.path.expanduser("~/lm-e2e-settings"))
def test_ensure_settings_file_pins_path_and_skips_migration(self, tmp_path, monkeypatch):
_redirect_paths(tmp_path, monkeypatch)
repo = tmp_path / "repo"
repo.mkdir()
legacy = repo / "settings.json"
legacy.write_text(json.dumps({"language": "ja"}), encoding="utf-8")
custom_dir = tmp_path / "custom"
monkeypatch.setenv(SETTINGS_DIR_ENV, str(custom_dir))
settings_file = ensure_settings_file()
assert settings_file == os.path.join(os.path.abspath(str(custom_dir)), "settings.json")
assert os.path.isdir(str(custom_dir))
# The legacy (project-root) file must NOT be migrated into the custom dir.
assert legacy.exists()
assert not (custom_dir / "settings.json").exists()
assert not (tmp_path / "user_config" / "settings.json").exists()
def test_programmatic_override_and_clear(self, tmp_path, monkeypatch):
_redirect_paths(tmp_path, monkeypatch)
monkeypatch.delenv(SETTINGS_DIR_ENV, raising=False)
custom_dir = tmp_path / "prog"
previous = set_settings_dir_override(str(custom_dir))
assert previous is None
assert is_settings_dir_pinned()
assert get_settings_dir(create=False) == os.path.abspath(str(custom_dir))
previous = set_settings_dir_override(None)
assert previous == os.path.abspath(str(custom_dir))
assert not is_settings_dir_pinned()
# Falls back to the (redirected) platform user config dir.
assert get_settings_dir(create=False) == str(tmp_path / "user_config")