b4fbd6fe9f
Deploy Site / deploy-vercel (push) Has been skipped
Deploy Site / deploy-docs (push) Has been skipped
Build Skills Index / build-index (push) Has been skipped
CI / Deny unrelated histories (push) Has been skipped
CI / Detect affected areas (push) Successful in 27m35s
CI / OSV scan (push) Failing after 4s
CI / Build&Test Docker image (push) Successful in 9s
CI / Supply-chain scan (push) Has been skipped
CI / Lint Docker scripts (push) Failing after 5m13s
CI / Check contributors (push) Failing after 12m8s
CI / Docs Site (push) Failing after 12m8s
CI / TypeScript (push) Failing after 12m8s
CI / Python lints (push) Failing after 12m9s
CI / Python tests (push) Failing after 12m9s
CI / Check uv.lock (push) Failing after 23m22s
CI / CI timing report (push) Has been cancelled
Build Skills Index / trigger-deploy (push) Has been cancelled
CI / All required checks pass (push) Has been cancelled
98 lines
3.6 KiB
Python
98 lines
3.6 KiB
Python
"""Config integration tests — managed scope wins over user config at the leaf."""
|
|
import textwrap
|
|
|
|
import pytest
|
|
|
|
|
|
@pytest.fixture
|
|
def homes(tmp_path, monkeypatch):
|
|
home = tmp_path / "home"
|
|
home.mkdir()
|
|
managed = tmp_path / "managed"
|
|
managed.mkdir()
|
|
monkeypatch.setenv("HERMES_HOME", str(home))
|
|
monkeypatch.setenv("HERMES_MANAGED_DIR", str(managed))
|
|
import hermes_cli.config as cfg
|
|
from hermes_cli import managed_scope
|
|
|
|
cfg._LOAD_CONFIG_CACHE.clear()
|
|
cfg._RAW_CONFIG_CACHE.clear()
|
|
managed_scope.invalidate_managed_cache()
|
|
return home, managed
|
|
|
|
|
|
def _write(path, body):
|
|
path.write_text(textwrap.dedent(body), encoding="utf-8")
|
|
import hermes_cli.config as cfg
|
|
from hermes_cli import managed_scope
|
|
|
|
cfg._LOAD_CONFIG_CACHE.clear()
|
|
cfg._RAW_CONFIG_CACHE.clear()
|
|
managed_scope.invalidate_managed_cache()
|
|
|
|
|
|
def test_managed_beats_user(homes):
|
|
from hermes_cli.config import load_config, cfg_get
|
|
|
|
home, managed = homes
|
|
_write(home / "config.yaml", "model:\n default: user/model\n")
|
|
_write(managed / "config.yaml", "model:\n default: managed/model\n")
|
|
assert cfg_get(load_config(), "model", "default") == "managed/model"
|
|
|
|
|
|
def test_managed_leaf_does_not_freeze_siblings(homes):
|
|
"""D3/Q4: pinning model.default leaves model.fallback user-controlled."""
|
|
from hermes_cli.config import load_config, cfg_get
|
|
|
|
home, managed = homes
|
|
_write(home / "config.yaml", "model:\n default: user/model\n fallback: user/fb\n")
|
|
_write(managed / "config.yaml", "model:\n default: managed/model\n")
|
|
cfg = load_config()
|
|
assert cfg_get(cfg, "model", "default") == "managed/model"
|
|
assert cfg_get(cfg, "model", "fallback") == "user/fb" # sibling preserved
|
|
|
|
|
|
def test_no_managed_config_is_unchanged(homes):
|
|
from hermes_cli.config import load_config, cfg_get
|
|
|
|
home, _ = homes
|
|
_write(home / "config.yaml", "model:\n default: user/model\n")
|
|
assert cfg_get(load_config(), "model", "default") == "user/model"
|
|
|
|
|
|
def test_managed_list_wins_wholesale(homes):
|
|
"""D3: a managed list value replaces the user's wholesale."""
|
|
from hermes_cli.config import load_config, cfg_get
|
|
|
|
home, managed = homes
|
|
_write(home / "config.yaml", "toolsets:\n enabled: [a, b, c]\n")
|
|
_write(managed / "config.yaml", "toolsets:\n enabled: [x]\n")
|
|
assert cfg_get(load_config(), "toolsets", "enabled") == ["x"]
|
|
|
|
|
|
def test_editing_managed_file_invalidates_cache(homes):
|
|
from hermes_cli.config import load_config, cfg_get
|
|
|
|
home, managed = homes
|
|
_write(home / "config.yaml", "model:\n default: user/model\n")
|
|
_write(managed / "config.yaml", "model:\n default: managed/v1\n")
|
|
assert cfg_get(load_config(), "model", "default") == "managed/v1"
|
|
_write(managed / "config.yaml", "model:\n default: managed/v2\n")
|
|
assert cfg_get(load_config(), "model", "default") == "managed/v2"
|
|
|
|
|
|
def test_user_cannot_shadow_managed_literal_via_envref(homes, monkeypatch):
|
|
"""A managed literal must NOT be expandable via a ${VAR} the user controls.
|
|
|
|
The managed value is a plain literal 'managed/locked' with no ${...}, so a
|
|
user-defined env var has nothing to substitute. This asserts the managed
|
|
literal survives verbatim regardless of user env, and that managed wins.
|
|
"""
|
|
from hermes_cli.config import load_config, cfg_get
|
|
|
|
home, managed = homes
|
|
monkeypatch.setenv("EVIL", "user/override")
|
|
_write(home / "config.yaml", "model:\n default: ${EVIL}\n")
|
|
_write(managed / "config.yaml", "model:\n default: managed/locked\n")
|
|
assert cfg_get(load_config(), "model", "default") == "managed/locked"
|