From ffeb7d8c972c2e6840d0682ef9e1959b788c5756 Mon Sep 17 00:00:00 2001 From: red person Date: Wed, 3 Jun 2026 02:57:35 +0300 Subject: [PATCH] Reject invalid preset CLI entries (#1579) * Reject invalid preset CLI entries * Use modern preset CLI test loader --- scripts/odysseus-preset | 18 ++++++++++----- tests/test_preset_cli_invalid_entries.py | 29 ++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 tests/test_preset_cli_invalid_entries.py diff --git a/scripts/odysseus-preset b/scripts/odysseus-preset index ce08f6d..3d47519 100755 --- a/scripts/odysseus-preset +++ b/scripts/odysseus-preset @@ -49,6 +49,15 @@ def _save(data: dict) -> None: tmp.replace(_PATH) +def _entry_or_fail(presets: dict, name: str) -> dict: + if name not in presets: + fail(f"no preset named {name!r}") + entry = presets[name] + if not isinstance(entry, dict): + fail(f"preset {name!r} is corrupt: expected an object") + return entry + + def cmd_list(args): presets = _load() rows = [] @@ -66,9 +75,7 @@ def cmd_list(args): def cmd_get(args): presets = _load() - if args.name not in presets: - fail(f"no preset named {args.name!r}") - emit({"id": args.name, **presets[args.name]}, args) + emit({"id": args.name, **_entry_or_fail(presets, args.name)}, args) def cmd_set(args): @@ -93,9 +100,8 @@ def cmd_set(args): def cmd_delete(args): presets = _load() - if args.name not in presets: - fail(f"no preset named {args.name!r}") - snap = presets.pop(args.name) + snap = _entry_or_fail(presets, args.name) + presets.pop(args.name) _save(presets) emit({"ok": True, "deleted": {"id": args.name, **snap}}, args) diff --git a/tests/test_preset_cli_invalid_entries.py b/tests/test_preset_cli_invalid_entries.py new file mode 100644 index 0000000..11110e1 --- /dev/null +++ b/tests/test_preset_cli_invalid_entries.py @@ -0,0 +1,29 @@ +import importlib.machinery +import importlib.util +from pathlib import Path + + +def _load_preset_cli(): + path = Path(__file__).resolve().parent.parent / "scripts" / "odysseus-preset" + loader = importlib.machinery.SourceFileLoader("odysseus_preset_invalid_entries", str(path)) + spec = importlib.util.spec_from_loader(loader.name, loader) + module = importlib.util.module_from_spec(spec) + loader.exec_module(module) + return module + + +def test_entry_or_fail_rejects_non_object_entries(): + cli = _load_preset_cli() + + try: + cli._entry_or_fail({"broken": "raw prompt"}, "broken") + except SystemExit as exc: + assert exc.code == 1 + else: + raise AssertionError("expected invalid preset entry to exit") + + +def test_entry_or_fail_returns_valid_entry(): + cli = _load_preset_cli() + + assert cli._entry_or_fail({"ok": {"name": "ok"}}, "ok") == {"name": "ok"}