test(tools): trim the salvaged #110632 / #110307 tests to two invariants each

The file-safety salvage carried five tests and the execute_code salvage four;
fold them into the two behaviour contracts per fix: (a) the named-profile scope
exempts the root's direct files and the write lands with no prompt; a child env
sees the ACTIVE profile's home per turn; (b) negatives hold: a checkout's
.hermes/config.yaml stays gated fail-closed, a lookalike profiles/ tree exempts
nothing; a dedicated process with no override is untouched. Both red on base.
Also compress the _hermes_exempt_homes docstring (WHY only; cite #110630).
This commit is contained in:
teknium1
2026-09-14 11:03:05 -07:00
committed by Teknium
parent 90a65d6e38
commit 818d781c0b
3 changed files with 50 additions and 112 deletions
+7 -23
View File
@@ -42,12 +42,14 @@ def _child_env():
class TestMultiplexedHermesHome:
def test_override_rewrites_stale_server_default(self, monkeypatch, home_override, tmp_path):
"""The reported bug: child must see the active profile's home, not the server default."""
def test_override_rewrites_stale_server_default_per_turn(self, monkeypatch, home_override, tmp_path):
"""The reported bug: a child must see the ACTIVE profile's home, not the server default,
and sequential turns for different profiles each see their own."""
monkeypatch.setenv("HERMES_HOME", "/machine/default/.hermes")
alpha_home = home_override(tmp_path / "profiles" / "alpha")
assert _child_env()["HERMES_HOME"] == alpha_home
alpha = home_override(tmp_path / "profiles" / "alpha")
assert _child_env()["HERMES_HOME"] == alpha
beta = home_override(tmp_path / "profiles" / "beta")
assert _child_env()["HERMES_HOME"] == beta
def test_no_override_leaves_inherited_value_untouched(self, monkeypatch):
"""Dedicated per-profile processes (no override): zero behavior change."""
@@ -55,21 +57,3 @@ class TestMultiplexedHermesHome:
monkeypatch.setenv("HERMES_HOME", "/machine/default/.hermes")
assert _child_env()["HERMES_HOME"] == "/machine/default/.hermes"
def test_override_applies_when_parent_env_unset(self, monkeypatch, home_override, tmp_path):
monkeypatch.delenv("HERMES_HOME", raising=False)
beta_home = home_override(tmp_path / "profiles" / "beta")
assert _child_env()["HERMES_HOME"] == beta_home
def test_override_does_not_leak_between_profiles(self, monkeypatch, home_override, tmp_path):
"""Sequential turns for different profiles each see their own home."""
monkeypatch.setenv("HERMES_HOME", "/machine/default/.hermes")
home_override(tmp_path / "profiles" / "alpha")
first = _child_env()["HERMES_HOME"]
home_override(tmp_path / "profiles" / "beta")
second = _child_env()["HERMES_HOME"]
assert first == str(tmp_path / "profiles" / "alpha")
assert second == str(tmp_path / "profiles" / "beta")
+34 -77
View File
@@ -736,100 +736,57 @@ class TestProfileHomeExemptsHermesRoot:
(root / "config.yaml").write_text("model:\n default: x\n", encoding="utf-8")
return root, profile
def test_profile_home_exempts_root_direct_files(
self, tmp_path, monkeypatch, approvals
):
"""Positive: the root's own store is not project-local ``.hermes`` config."""
def test_named_profile_scope_exempts_root_direct_files(self, tmp_path, monkeypatch, approvals):
"""Under a named profile bound by the per-turn scope (multiplex path), the ROOT's own store is
not project-local ``.hermes`` config: the write lands with no approval prompt."""
import tools.file_tools_write_guards as ft
from hermes_constants import reset_hermes_home_override, set_hermes_home_override
root, profile = self._profile_layout(tmp_path)
monkeypatch.setenv("HERMES_HOME", str(profile))
assert os.path.realpath(str(profile)) in ft._hermes_exempt_homes()
assert os.path.realpath(str(root)) in ft._hermes_exempt_homes()
for name in ("LEDGER.md", "MEMORY.md", "USER.md", "SOUL.md", "AGENTS.md"):
reason = ft._protected_instruction_reason(str(root / name))
assert reason is None, f"{name} misread as project-local .hermes config"
# …and the write actually lands, with no approval prompt at all.
res = self._write(root / "LEDGER.md", "caliber fixed")
monkeypatch.delenv("HERMES_HOME", raising=False)
token = set_hermes_home_override(str(profile))
try:
assert os.path.realpath(str(root)) in ft._hermes_exempt_homes()
for name in ("LEDGER.md", "MEMORY.md", "SOUL.md", "AGENTS.md"):
assert ft._protected_instruction_reason(str(root / name)) is None, name
res = self._write(root / "LEDGER.md", "caliber fixed")
finally:
reset_hermes_home_override(token)
assert not res.get("error"), res
assert (root / "LEDGER.md").read_text(encoding="utf-8") == "caliber fixed"
assert approvals["calls"] == []
def test_negatives_still_gated_under_profile_home(
self, tmp_path, monkeypatch, approvals
):
"""Negative samples must keep failing closed with the profile home active."""
def test_only_a_real_hermes_root_is_exempt(self, tmp_path, monkeypatch, approvals):
"""Negatives hold with a named profile active: a checkout's ``.hermes/config.yaml`` and
protected basenames stay gated (fail-closed, unwritten), and a coincidental
``.../profiles/<name>`` tree that is NOT a Hermes root never exempts its parent."""
import tools.file_tools_write_guards as ft
from hermes_constants import reset_hermes_home_override, set_hermes_home_override
root, profile = self._profile_layout(tmp_path)
repo = tmp_path / "repo" # a checkout OUTSIDE the Hermes tree
repo = tmp_path / "repo"
(repo / ".hermes").mkdir(parents=True)
monkeypatch.setenv("HERMES_HOME", str(profile))
assert ft._protected_instruction_reason(str(repo / ".hermes" / "config.yaml"))
for name in ("AGENTS.md", "SOUL.md", "CLAUDE.md"):
assert ft._protected_instruction_reason(str(repo / name)) == name
assert ft._protected_instruction_reason("/tmp/elsewhere/docs/AGENTS.md")
# End-to-end: the project-local .hermes config is still refused, unwritten.
target = repo / ".hermes" / "config.yaml"
res = self._write(target, "gate: off\n")
monkeypatch.delenv("HERMES_HOME", raising=False)
token = set_hermes_home_override(str(profile))
try:
assert ft._protected_instruction_reason(str(repo / ".hermes" / "config.yaml"))
assert ft._protected_instruction_reason(str(repo / "AGENTS.md")) == "AGENTS.md"
target = repo / ".hermes" / "config.yaml"
res = self._write(target, "gate: off\n")
finally:
reset_hermes_home_override(token)
assert res.get("error") and "BLOCKED" in res["error"]
assert not target.exists()
assert len(approvals["calls"]) == 1
def test_lookalike_profiles_dir_does_not_exempt_parent(
self, tmp_path, monkeypatch
):
"""Only a REAL Hermes root is exempt; a coincidental ``profiles/`` dir is not.
The root is derived from the ACTIVE home (contextvar scope — the multiplex
path), not from ``HERMES_HOME``, so a random ``.../profiles/<name>`` tree
cannot quietly exempt its parent directory.
"""
import tools.file_tools_write_guards as ft
from hermes_constants import reset_hermes_home_override, set_hermes_home_override
fake = tmp_path / "not-a-hermes-root"
profile = fake / "profiles" / "worker"
profile.mkdir(parents=True)
monkeypatch.delenv("HERMES_HOME", raising=False)
token = set_hermes_home_override(str(profile))
fake_profile = tmp_path / "not-a-hermes-root" / "profiles" / "worker"
fake_profile.mkdir(parents=True)
token = set_hermes_home_override(str(fake_profile))
try:
assert ft._hermes_exempt_homes() == (os.path.realpath(str(profile)),)
proj = fake / "proj" / ".hermes"
proj.mkdir(parents=True)
assert ft._protected_instruction_reason(str(proj / "config.yaml"))
assert ft._hermes_exempt_homes() == (os.path.realpath(str(fake_profile)),)
finally:
reset_hermes_home_override(token)
def test_multiplex_profile_scope_exempts_root(
self, tmp_path, monkeypatch
):
"""The contextvar scope (multiplex gateway) resolves the root the same way."""
import tools.file_tools_write_guards as ft
from hermes_constants import reset_hermes_home_override, set_hermes_home_override
root, _profile = self._profile_layout(tmp_path)
alpha = root / "profiles" / "alpha"
alpha.mkdir(parents=True)
monkeypatch.delenv("HERMES_HOME", raising=False)
token = set_hermes_home_override(str(alpha))
try:
assert os.path.realpath(str(root)) in ft._hermes_exempt_homes()
assert ft._protected_instruction_reason(str(root / "LEDGER.md")) is None
finally:
reset_hermes_home_override(token)
def test_default_profile_exemption_unchanged(self, tmp_path, monkeypatch):
"""HERMES_HOME=<root> (default profile): one exempt tree, as before."""
import tools.file_tools_write_guards as ft
root, _profile = self._profile_layout(tmp_path)
monkeypatch.setenv("HERMES_HOME", str(root))
assert ft._hermes_exempt_homes() == (os.path.realpath(str(root)),)
assert ft._protected_instruction_reason(str(root / "LEDGER.md")) is None
class TestMultiplexProfileWriteGuardsAreProfileScoped:
"""#107327: a multiplexed gateway scopes ``HERMES_HOME`` per turn via a
+9 -12
View File
@@ -101,18 +101,15 @@ def _get_real_hermes_home() -> str | None:
def _hermes_exempt_homes() -> tuple[str, ...]:
"""Realpaths of the Hermes home tree(s) the protected-instruction gate must stay out of.
Always the ACTIVE profile's home; PLUS the Hermes ROOT when that home is a named
profile (``<root>/profiles/<name>``). Exempting only the profile dir left the root's
DIRECT files (LEDGER.md / MEMORY.md / SOUL.md / AGENTS.md / DECISIONS.md ...) to fall
through to the ``.hermes`` component rule in ``_protected_instruction_reason``, which
then gated them as if they were a project-local ``<repo>/.hermes/config.yaml`` — and
that gate has no approval channel headless, so every write there failed closed (#60;
it blocked #54). Those files are the agent's own store, governed by their own guards,
exactly like ``~/.hermes`` under the default profile. The root is only added when the
shape really is a named profile (``named_profile_home``), so a coincidental
``profiles/`` directory elsewhere never exempts its parent."""
"""Realpaths of the Hermes home tree(s) the protected-instruction gate must stay out of:
the ACTIVE profile's home, plus the Hermes ROOT when that home is a named profile
(``<root>/profiles/<name>``). Exempting only the profile dir left the root's DIRECT files
(LEDGER.md / MEMORY.md / SOUL.md / AGENTS.md ...) to the ``.hermes`` component rule, which
gated them like a project-local ``<repo>/.hermes/config.yaml`` — fail-closed headless
(#110630). They are the agent's own store, governed by their own guards, exactly like
``~/.hermes`` under the default profile. The root is added only when the shape really is a
named profile (``named_profile_home``), so a coincidental ``profiles/`` dir elsewhere never
exempts its parent; the home comes from the ACTIVE scope, never ``HERMES_HOME`` alone."""
home = _get_real_hermes_home()
if not home:
return ()