fix(gateway): owner names a managed approvals.mode when it refuses the write

approvals.mode and yolo with scope=global were already refused when the
managed scope pins approvals.mode (set_config_value refuses it), but the
owner reported storage_unavailable. It now reports permission_denied with
field=approvals.mode, like the other owner config.set refusals. Nothing is
written either way, and any other failure keeps storage_unavailable.
This commit is contained in:
unsupportedpastels authored and Mark S. committed 2026-11-05 18:27:43 -05:00
1 parent 2dc7afd82e
commit 8987ae565f
2 files changed
+23

No files matched your search

+3
View File
@@ -341,6 +341,9 @@ def _set_approval_mode(connection, value):
with _profile_runtime_scope(Path(connection.authority.profile_id)), _WRITE_LOCK:
result = run_approval_mode_command(_word(value) or None)
if not result.ok:
from hermes_cli.managed_scope import is_key_managed
if _word(value) in ('manual', 'smart', 'off') and is_key_managed('approvals.mode'):
raise _managed_refusal('approvals.mode') # set_config_value refused it: name the key
raise RuntimeStoreError('invalid_params' if _word(value) not in ('manual', 'smart', 'off')
else 'storage_unavailable')
return {'key': 'approvals.mode', 'value': result.mode}
@@ -100,3 +100,23 @@ def test_owner_global_reasoning_level_is_refused_before_anything_changes(home, m
else:
assert run() == {"key": "reasoning", "value": "high", "scope": scope}
assert calls == [("commit", scope == "global"), ("apply", scope == "global")]
@pytest.mark.parametrize("pins_mode", [True, False], ids=["managed", "unmanaged"])
def test_owner_approval_mode_refusal_names_a_pinned_key(home, monkeypatch, pins_mode):
"""A refused ``approvals.mode`` write reports ``permission_denied`` naming the key when the managed
scope pins it; any other refusal keeps ``storage_unavailable``. Nothing is written either way."""
from gateway import session_tui_config
from hermes_cli import approval_mode, managed_scope
if pins_mode:
(home.parent / "managed" / "config.yaml").write_text("approvals:\n mode: manual\n")
managed_scope.invalidate_managed_cache()
else:
monkeypatch.setattr(approval_mode, "run_approval_mode_command",
lambda mode: SimpleNamespace(ok=False, mode="manual"))
connection = SimpleNamespace(authority=SimpleNamespace(profile_id=str(home)))
with pytest.raises(RuntimeStoreError) as refused:
session_tui_config._set_approval_mode(connection, "off")
expected = ("permission_denied", "approvals.mode") if pins_mode else ("storage_unavailable", None)
assert (refused.value.reason, refused.value.field) == expected
assert yaml.safe_load((home / "config.yaml").read_text()) == {"display": {"tui_theme": "dark"}}