Files
hermes-agent/tests/pm/test_store_extensions.py
ethernet a00ca233f8 fix(pm): voice enables audio-io through PM; public plugin-state readers; PM tests isolate the machine home
- voice_mode: `_import_audio` asks `pm.ensure_import("audio-io")` before importing
  sounddevice, so `/voice on` turns the feature on (or reports exactly why PM
  refused: lazy installs off, platform gate, restart needed) instead of printing a
  `python -c "from pm import sync_venv…"` one-liner for the user to run.
- pm.plugins_state: `read_home_selection` and `dependency_homes` are the public
  readers; memory_provider_migration and plugins_cmd stop importing underscored names.
- pm.store: the `sha256_file` shim is gone; the authority test asserts the Store has no
  file hash of its own rather than patching one.
- tests/pm/conftest: `isolated_machine_home` is autouse (Path.home, HOME, USERPROFILE,
  HERMES_HOME all under tmp_path); `@pytest.mark.real_machine_home` opts a module out
  — the four suites that spawn children with a home they build themselves.
- activate / activate.ps1 / Dockerfile followed hermes_cli.runtime_paths to
  pm.environments (the earlier sweep only covered .py).
- pm.registry loads builtins through importlib so a test patching `pm.packages` in
  sys.modules still registers the security packages.
2026-09-19 00:48:11 -04:00

46 lines
2.1 KiB
Python

"""A bundle reuses shipped bytes and adds missing pinned tools outside its seal."""
import pytest
import pm.paths as paths
from pm.lock import Facts
from tests.pm.test_pm_authority import core_env, pm_env, served # noqa: F401 — fixtures
@pytest.mark.parametrize("sealed_install", [True, False])
def test_missing_bundle_tool_is_installed_in_writable_store(pm_env, tmp_path, monkeypatch, sealed_install):
from pm.install import ensure, env_for, is_installed
import importlib
fixture = pm_env
shipped = tmp_path / "payload" / "tools"
shipped.mkdir(parents=True)
(shipped.parent / "manifest.json").write_text('{"repo":"core","store":"tools","venv":"venv"}')
monkeypatch.setattr(paths, "store_root", lambda: shipped)
monkeypatch.setattr(paths, "facts_path", lambda: shipped / "facts.json")
monkeypatch.setenv("HERMES_HOME", str(tmp_path / "home"))
ensure_module = importlib.import_module("pm.install")
monkeypatch.setattr(ensure_module, "lazy_installs_allowed", lambda: True)
monkeypatch.setattr(ensure_module, "sealed", lambda: sealed_install)
before = sorted(p.relative_to(shipped).as_posix() for p in shipped.rglob("*"))
runner = ensure("faketool", explicit=True, base_env={})
assert is_installed("faketool")
assert sorted(p.relative_to(shipped).as_posix() for p in shipped.rglob("*")) == before
writable = paths.writable_store_root()
fact = Facts(writable / "facts.json").get("faketool")
assert fact is not None and (writable / fact["entry"] / "bin" / "faketool").is_file()
assert str(writable) in runner.env["PATH"]
assert env_for("faketool", base_env={}) == runner.env
def test_corrupt_shipped_facts_are_only_read(tmp_path, monkeypatch):
store = tmp_path / "payload" / "tools"
store.mkdir(parents=True)
(store.parent / "manifest.json").write_text("{}")
facts = store / "facts.json"
facts.write_text("{broken")
monkeypatch.setattr(paths, "store_root", lambda: store)
assert Facts(facts).get("anything") is None
assert facts.read_text() == "{broken"
assert not facts.with_suffix(".corrupt").exists()