From 1dab14d2985b399d5822424872e4132557b17fa9 Mon Sep 17 00:00:00 2001 From: Harwinder Sekhon Date: Tue, 21 Jul 2026 12:54:46 -0400 Subject: [PATCH] app_config: reject non-object config.json sections with AppConfigError Claude-Session: https://claude.ai/code/session_01VPNF37MP9Kuv62B1VBrZ1b --- app_config.py | 4 ++++ test_all.py | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/app_config.py b/app_config.py index cd8ebf9..6adb3e7 100644 --- a/app_config.py +++ b/app_config.py @@ -66,6 +66,8 @@ class AppConfig: def _check_keys(section: Dict[str, Any], known: set, where: str) -> None: + if not isinstance(section, dict): + raise AppConfigError(f"config.json: {where} must be a JSON object") unknown = sorted(set(section) - known) if unknown: raise AppConfigError( @@ -141,6 +143,8 @@ def load_app_config(path: str = CONFIG_PATH) -> AppConfig: app.scan_timeframes = [Timeframe[n] for n in names] pair_section = raw.get("pairs", {}) + if not isinstance(pair_section, dict): + raise AppConfigError('config.json: "pairs" must be a JSON object') for symbol, overrides in pair_section.items(): if symbol not in PAIR_INFO: raise AppConfigError( diff --git a/test_all.py b/test_all.py index 2f169a8..ed0dfe7 100644 --- a/test_all.py +++ b/test_all.py @@ -2661,6 +2661,22 @@ def _(): assert telegram_channel_id(app) == "" +@test("app_config: non-object sections raise AppConfigError") +def _(): + for payload in ( + {"telegram": None}, + {"telegram": "oops"}, + {"scanning": 5}, + {"pairs": ["oops"]}, + {"pairs": {"XAU/USD": ["blocked_hours_utc"]}}, + ): + try: + load_app_config(_write_json(payload)) + assert False, f"should have raised for {payload}" + except AppConfigError: + pass + + # ══════════════════════════════════════════════════════════════════════ # SUMMARY # ══════════════════════════════════════════════════════════════════════