# -*- coding: utf-8 -*- """t-261001091912-24602f: ROUTER_BASE_URL/ключ берётся и из .env, не только из env. Запуск: ./venv/bin/python tests/test_router_env_fallback.py Баг в e2e: systemd-юниты харнеса не экспортируют .env, runtime.py читал ROUTER_BASE_URL только из окружения → у свежеразвёрнутого агента base_url тихо уходил в дефолт 127.0.0.1:20128 (на эталонном хосте так жив 9router, на Hetzner-агенте — нет) и LLM-тики падали до первого look в .env. Фикс: _env_or_file() — env имеет приоритет, .env рядом с кодом — фолбэк (как раньше делал _router_key); EnvironmentFile в юнитах cloud-init — страховка сверху. """ import os import sys import tempfile sys.path.insert(0, "/root/simbiot-harness") fails = [] def check(name, cond, extra=""): print(("PASS" if cond else "FAIL"), name, ("| " + extra) if not cond else "") if not cond: fails.append(name) # изоляция стора (аудит 2026-10-16): тест не пишет в боевой стор, даже # когда его гоняет тик харнеса под SIMBIOT_HOME (TTFTWatchdogRetry с # бюджетом 0.5с из этого набора оседали в проде) import tempfile as _iso_tf # noqa: E402 os.environ["SIMBIOT_DB"] = os.path.join(_iso_tf.mkdtemp(prefix="simbiot_test_"), "harness.db") from harness import runtime # hermetic: окружение тест-процесса не должно подсказывать значения for _v in ("ROUTER_BASE_URL", "ROUTER_KEY", "OPENAI_API_KEY", "OPENAI_BASE_URL"): os.environ.pop(_v, None) # временный "каталог харнеса" с фейковым .env — реальный не трогаем tmpdir = tempfile.mkdtemp(prefix="simbiot-envtest-") with open(os.path.join(tmpdir, ".env"), "w") as f: f.write("ROUTER_BASE_URL=https://router.cil.by/v1\n") f.write("ROUTER_KEY=sk-envtest-key\n") f.write("# комментарий\n") # t-261004113351: runtime читает .env через paths.env_path() (SIMBIOT_HOME), # _HARNESS_DIR больше не источник — патчим актуальный механизм (с рестором) runtime._paths.env_path = lambda: os.path.join(tmpdir, ".env") # 1. env отсутствует, .env есть → значение из .env (суть фикса) check("1: base_url из .env quando env пуст", runtime._router_base_url() == "https://router.cil.by/v1", str(runtime._router_base_url())) check("1: ключ из .env (прежнее поведение сохранено)", runtime._router_key() == "sk-envtest-key") # 2. env присутствует → env сильнее .env os.environ["ROUTER_BASE_URL"] = "https://env.takes/priority/v1" check("2: env приоритетнее .env", runtime._router_base_url() == "https://env.takes/priority/v1") os.environ.pop("ROUTER_BASE_URL") # 3. нет ни env, ни .env → дефолт с локальным роутером runtime._paths.env_path = lambda: os.path.join( tempfile.mkdtemp(prefix="simbiot-envtest-empty-"), ".env") check("3: нет .env → дефолт 127.0.0.1:20128", runtime._router_base_url() == "http://127.0.0.1:20128/v1", str(runtime._router_base_url())) # 4. setup_provider(): end-to-end маппинг .env → OPENAI_* env runtime._paths.env_path = lambda: os.path.join(tmpdir, ".env") runtime.setup_provider() check("4: setup_provider кладёт OPENAI_BASE_URL из .env", os.environ["OPENAI_BASE_URL"] == "https://router.cil.by/v1", os.environ.get("OPENAI_BASE_URL", "")) check("4: setup_provider кладёт OPENAI_API_KEY из .env", os.environ.get("OPENAI_API_KEY") == "sk-envtest-key") print() print("FAILS:", len(fails), "| файл:", " | ".join(fails) if fails else "—") sys.exit(1 if fails else 0)