Merge #4028 (align profile cookie env var with HERMES_WEBUI_ prefix) onto master
This commit is contained in:
@@ -495,11 +495,36 @@ def read_body(handler) -> dict:
|
||||
# ── Profile cookie helpers (issue #798) ─────────────────────────────────────
|
||||
|
||||
PROFILE_COOKIE_NAME = 'hermes_profile'
|
||||
_PROFILE_COOKIE_ENV = 'HERMES_WEBUI_PROFILE_COOKIE_NAME'
|
||||
_LEGACY_PROFILE_COOKIE_ENV = 'WEBUI_PROFILE_COOKIE_NAME'
|
||||
_legacy_profile_cookie_warned = False
|
||||
|
||||
|
||||
def get_profile_cookie_name() -> str:
|
||||
"""Return the cookie name used to persist the active WebUI profile."""
|
||||
return os.getenv('WEBUI_PROFILE_COOKIE_NAME', PROFILE_COOKIE_NAME)
|
||||
"""Return the cookie name used to persist the active WebUI profile.
|
||||
|
||||
Honours ``HERMES_WEBUI_PROFILE_COOKIE_NAME`` so multiple WebUI instances
|
||||
sharing a hostname (different ports) can use distinct profile-cookie names
|
||||
instead of trampling each other; browsers scope cookies by host, not
|
||||
host+port (RFC 6265). The original ``WEBUI_PROFILE_COOKIE_NAME`` is still
|
||||
honoured as a deprecated fallback (warned once per process, since this is
|
||||
called on every request).
|
||||
"""
|
||||
name = os.getenv(_PROFILE_COOKIE_ENV, '').strip()
|
||||
if name:
|
||||
return name
|
||||
legacy = os.getenv(_LEGACY_PROFILE_COOKIE_ENV, '').strip()
|
||||
if legacy:
|
||||
global _legacy_profile_cookie_warned
|
||||
if not _legacy_profile_cookie_warned:
|
||||
logger.warning(
|
||||
'%s is deprecated; use %s instead.',
|
||||
_LEGACY_PROFILE_COOKIE_ENV,
|
||||
_PROFILE_COOKIE_ENV,
|
||||
)
|
||||
_legacy_profile_cookie_warned = True
|
||||
return legacy
|
||||
return PROFILE_COOKIE_NAME
|
||||
|
||||
|
||||
def get_profile_cookie(handler) -> str | None:
|
||||
|
||||
@@ -13,6 +13,7 @@ Covers:
|
||||
4. switch_profile(process_wide=False) does NOT mutate process globals
|
||||
5. Concurrent requests on different threads see independent profiles
|
||||
"""
|
||||
import logging
|
||||
import os
|
||||
import threading
|
||||
from pathlib import Path
|
||||
@@ -230,6 +231,60 @@ class TestProfileCookieHelpers:
|
||||
assert get_profile_cookie(handler) is None
|
||||
|
||||
|
||||
# ── 1b. Profile cookie name resolution (env > legacy env > default) ───────────
|
||||
|
||||
class TestProfileCookieNameResolution:
|
||||
|
||||
def test_default_when_unset(self, monkeypatch):
|
||||
from api.helpers import PROFILE_COOKIE_NAME, get_profile_cookie_name
|
||||
monkeypatch.delenv('HERMES_WEBUI_PROFILE_COOKIE_NAME', raising=False)
|
||||
monkeypatch.delenv('WEBUI_PROFILE_COOKIE_NAME', raising=False)
|
||||
assert get_profile_cookie_name() == PROFILE_COOKIE_NAME
|
||||
|
||||
def test_canonical_env_overrides_default(self, monkeypatch):
|
||||
from api.helpers import get_profile_cookie_name
|
||||
monkeypatch.delenv('WEBUI_PROFILE_COOKIE_NAME', raising=False)
|
||||
monkeypatch.setenv('HERMES_WEBUI_PROFILE_COOKIE_NAME', 'hermes_profile_alt')
|
||||
assert get_profile_cookie_name() == 'hermes_profile_alt'
|
||||
|
||||
def test_legacy_env_still_honoured(self, monkeypatch):
|
||||
from api.helpers import get_profile_cookie_name
|
||||
monkeypatch.delenv('HERMES_WEBUI_PROFILE_COOKIE_NAME', raising=False)
|
||||
monkeypatch.setenv('WEBUI_PROFILE_COOKIE_NAME', 'hermes_profile_legacy')
|
||||
assert get_profile_cookie_name() == 'hermes_profile_legacy'
|
||||
|
||||
def test_canonical_takes_precedence_over_legacy(self, monkeypatch):
|
||||
from api.helpers import get_profile_cookie_name
|
||||
monkeypatch.setenv('HERMES_WEBUI_PROFILE_COOKIE_NAME', 'canonical')
|
||||
monkeypatch.setenv('WEBUI_PROFILE_COOKIE_NAME', 'legacy')
|
||||
assert get_profile_cookie_name() == 'canonical'
|
||||
|
||||
def test_blank_canonical_falls_back_to_legacy(self, monkeypatch):
|
||||
from api.helpers import get_profile_cookie_name
|
||||
monkeypatch.setenv('HERMES_WEBUI_PROFILE_COOKIE_NAME', ' ')
|
||||
monkeypatch.setenv('WEBUI_PROFILE_COOKIE_NAME', 'hermes_profile_legacy')
|
||||
assert get_profile_cookie_name() == 'hermes_profile_legacy'
|
||||
|
||||
def test_blank_envs_fall_back_to_default(self, monkeypatch):
|
||||
from api.helpers import PROFILE_COOKIE_NAME, get_profile_cookie_name
|
||||
monkeypatch.setenv('HERMES_WEBUI_PROFILE_COOKIE_NAME', ' ')
|
||||
monkeypatch.setenv('WEBUI_PROFILE_COOKIE_NAME', '')
|
||||
assert get_profile_cookie_name() == PROFILE_COOKIE_NAME
|
||||
|
||||
def test_legacy_deprecation_warns_only_once(self, monkeypatch, caplog):
|
||||
# get_profile_cookie_name() runs on every request, so the deprecation
|
||||
# warning for the legacy env var must be emitted once per process.
|
||||
import api.helpers as helpers
|
||||
monkeypatch.delenv('HERMES_WEBUI_PROFILE_COOKIE_NAME', raising=False)
|
||||
monkeypatch.setenv('WEBUI_PROFILE_COOKIE_NAME', 'hermes_profile_legacy')
|
||||
monkeypatch.setattr(helpers, '_legacy_profile_cookie_warned', False)
|
||||
with caplog.at_level(logging.WARNING, logger='api.helpers'):
|
||||
for _ in range(3):
|
||||
assert helpers.get_profile_cookie_name() == 'hermes_profile_legacy'
|
||||
warned = [r for r in caplog.records if 'deprecated' in r.getMessage()]
|
||||
assert len(warned) == 1
|
||||
|
||||
|
||||
# ── 2. Thread-local request context ──────────────────────────────────────────
|
||||
|
||||
class TestThreadLocalProfileContext:
|
||||
|
||||
Reference in New Issue
Block a user