fix(approval): recover legacy list values without character grants

Recover legacy stringified lists with a warning. Reject malformed shapes and nonstring members without admitting approvals or rewriting user config on read.

Fixes #104779
Co-authored-by: liuhao1024 <sunsky.lau@gmail.com>
This commit is contained in:
Teknium
2026-09-07 02:06:51 -07:00
parent ab1a6d016a
commit 7876d183c9
3 changed files with 44 additions and 1 deletions
@@ -0,0 +1,21 @@
import yaml
from tools import approval
def test_legacy_string_allowlist_recovers_only_string_lists(tmp_path, monkeypatch, caplog):
monkeypatch.setenv("HERMES_HOME", str(tmp_path))
description = "script execution via -e/-c flag"
for value in ([description], yaml.safe_dump([description])):
(tmp_path / "config.yaml").write_text(yaml.safe_dump({"command_allowlist": value}))
assert approval.load_permanent_allowlist() == {description}
assert approval.is_approved("probe", description)
assert "command_allowlist" in caplog.text
def test_malformed_allowlist_does_not_grant_approval(tmp_path, monkeypatch, caplog):
monkeypatch.setenv("HERMES_HOME", str(tmp_path))
for value in ("plain text", "[bad", {"not": "a list"}, [True, "candidate"], "[true, candidate]", 42):
(tmp_path / "config.yaml").write_text(yaml.safe_dump({"command_allowlist": value}))
assert approval.load_permanent_allowlist() == set()
assert not approval.is_approved("probe", "candidate")
assert "command_allowlist" in caplog.text
+17 -1
View File
@@ -330,7 +330,23 @@ def load_permanent_allowlist() -> set:
try:
from hermes_cli.config import load_config_readonly
config = load_config_readonly()
patterns = set(config.get("command_allowlist", []) or [])
raw = config.get("command_allowlist")
legacy = isinstance(raw, str)
if legacy:
# Old config-set versions serialized list values as scalar strings.
import yaml
try:
raw = yaml.safe_load(raw)
except yaml.YAMLError:
raw = False
if raw is None and not legacy:
raw = []
if not isinstance(raw, list) or any(not isinstance(item, str) for item in raw):
logger.warning("Ignoring malformed command_allowlist; configure a list of strings.")
return set()
if legacy:
logger.warning("Recovered legacy string command_allowlist; re-save it as a list of strings.")
patterns = set(raw)
if patterns:
load_permanent(patterns)
return patterns
+6
View File
@@ -262,6 +262,12 @@ command_allowlist:
These patterns are loaded at startup and silently approved in all future sessions.
The setting must be a list of strings. Legacy installs that stored a list as a
quoted YAML/JSON string recover that list at load time and log a warning to
re-save it with `hermes config edit`. Other malformed values are ignored with
a warning; they never become per-character approvals. Loading does not rewrite
your configuration file.
:::tip
Use `hermes config edit` to review or remove patterns from your permanent allowlist.
:::