Skip to content

Commit 1ae5679

Browse files
Merge pull request nesquena#4105 from nesquena/stage-4028
Release MX (v0.51.385): profile-cookie env var aligned to HERMES_WEBUI_ prefix (nesquena#803)
2 parents abe89f3 + a31466b commit 1ae5679

3 files changed

Lines changed: 88 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33

44
## [Unreleased]
55

6+
## [v0.51.385] — 2026-06-13 — Release MX (profile-cookie env var aligned to HERMES_WEBUI_ prefix, #803)
7+
8+
### Changed
9+
10+
- **The profile-cookie name env var now uses the standard `HERMES_WEBUI_` prefix (#803).** Set the per-instance session-profile cookie name via `HERMES_WEBUI_PROFILE_COOKIE_NAME`, matching every other WebUI setting's prefix; the original `WEBUI_PROFILE_COOKIE_NAME` keeps working as a deprecated fallback (warned once per process). Lets multiple WebUI instances on the same host+port disambiguate their profile cookies without env-var-naming surprises. (#803)
11+
612
## [v0.51.384] — 2026-06-13 — Release MW (no false streaming / activity-timer reset on session switch, #3900)
713

814
### Fixed

api/helpers.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -495,11 +495,36 @@ def read_body(handler) -> dict:
495495
# ── Profile cookie helpers (issue #798) ─────────────────────────────────────
496496

497497
PROFILE_COOKIE_NAME = 'hermes_profile'
498+
_PROFILE_COOKIE_ENV = 'HERMES_WEBUI_PROFILE_COOKIE_NAME'
499+
_LEGACY_PROFILE_COOKIE_ENV = 'WEBUI_PROFILE_COOKIE_NAME'
500+
_legacy_profile_cookie_warned = False
498501

499502

500503
def get_profile_cookie_name() -> str:
501-
"""Return the cookie name used to persist the active WebUI profile."""
502-
return os.getenv('WEBUI_PROFILE_COOKIE_NAME', PROFILE_COOKIE_NAME)
504+
"""Return the cookie name used to persist the active WebUI profile.
505+
506+
Honours ``HERMES_WEBUI_PROFILE_COOKIE_NAME`` so multiple WebUI instances
507+
sharing a hostname (different ports) can use distinct profile-cookie names
508+
instead of trampling each other; browsers scope cookies by host, not
509+
host+port (RFC 6265). The original ``WEBUI_PROFILE_COOKIE_NAME`` is still
510+
honoured as a deprecated fallback (warned once per process, since this is
511+
called on every request).
512+
"""
513+
name = os.getenv(_PROFILE_COOKIE_ENV, '').strip()
514+
if name:
515+
return name
516+
legacy = os.getenv(_LEGACY_PROFILE_COOKIE_ENV, '').strip()
517+
if legacy:
518+
global _legacy_profile_cookie_warned
519+
if not _legacy_profile_cookie_warned:
520+
logger.warning(
521+
'%s is deprecated; use %s instead.',
522+
_LEGACY_PROFILE_COOKIE_ENV,
523+
_PROFILE_COOKIE_ENV,
524+
)
525+
_legacy_profile_cookie_warned = True
526+
return legacy
527+
return PROFILE_COOKIE_NAME
503528

504529

505530
def get_profile_cookie(handler) -> str | None:

tests/test_issue803.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
4. switch_profile(process_wide=False) does NOT mutate process globals
1414
5. Concurrent requests on different threads see independent profiles
1515
"""
16+
import logging
1617
import os
1718
import threading
1819
from pathlib import Path
@@ -230,6 +231,60 @@ def test_configured_profile_cookie_ignores_default_cookie_name(self, monkeypatch
230231
assert get_profile_cookie(handler) is None
231232

232233

234+
# ── 1b. Profile cookie name resolution (env > legacy env > default) ───────────
235+
236+
class TestProfileCookieNameResolution:
237+
238+
def test_default_when_unset(self, monkeypatch):
239+
from api.helpers import PROFILE_COOKIE_NAME, get_profile_cookie_name
240+
monkeypatch.delenv('HERMES_WEBUI_PROFILE_COOKIE_NAME', raising=False)
241+
monkeypatch.delenv('WEBUI_PROFILE_COOKIE_NAME', raising=False)
242+
assert get_profile_cookie_name() == PROFILE_COOKIE_NAME
243+
244+
def test_canonical_env_overrides_default(self, monkeypatch):
245+
from api.helpers import get_profile_cookie_name
246+
monkeypatch.delenv('WEBUI_PROFILE_COOKIE_NAME', raising=False)
247+
monkeypatch.setenv('HERMES_WEBUI_PROFILE_COOKIE_NAME', 'hermes_profile_alt')
248+
assert get_profile_cookie_name() == 'hermes_profile_alt'
249+
250+
def test_legacy_env_still_honoured(self, monkeypatch):
251+
from api.helpers import get_profile_cookie_name
252+
monkeypatch.delenv('HERMES_WEBUI_PROFILE_COOKIE_NAME', raising=False)
253+
monkeypatch.setenv('WEBUI_PROFILE_COOKIE_NAME', 'hermes_profile_legacy')
254+
assert get_profile_cookie_name() == 'hermes_profile_legacy'
255+
256+
def test_canonical_takes_precedence_over_legacy(self, monkeypatch):
257+
from api.helpers import get_profile_cookie_name
258+
monkeypatch.setenv('HERMES_WEBUI_PROFILE_COOKIE_NAME', 'canonical')
259+
monkeypatch.setenv('WEBUI_PROFILE_COOKIE_NAME', 'legacy')
260+
assert get_profile_cookie_name() == 'canonical'
261+
262+
def test_blank_canonical_falls_back_to_legacy(self, monkeypatch):
263+
from api.helpers import get_profile_cookie_name
264+
monkeypatch.setenv('HERMES_WEBUI_PROFILE_COOKIE_NAME', ' ')
265+
monkeypatch.setenv('WEBUI_PROFILE_COOKIE_NAME', 'hermes_profile_legacy')
266+
assert get_profile_cookie_name() == 'hermes_profile_legacy'
267+
268+
def test_blank_envs_fall_back_to_default(self, monkeypatch):
269+
from api.helpers import PROFILE_COOKIE_NAME, get_profile_cookie_name
270+
monkeypatch.setenv('HERMES_WEBUI_PROFILE_COOKIE_NAME', ' ')
271+
monkeypatch.setenv('WEBUI_PROFILE_COOKIE_NAME', '')
272+
assert get_profile_cookie_name() == PROFILE_COOKIE_NAME
273+
274+
def test_legacy_deprecation_warns_only_once(self, monkeypatch, caplog):
275+
# get_profile_cookie_name() runs on every request, so the deprecation
276+
# warning for the legacy env var must be emitted once per process.
277+
import api.helpers as helpers
278+
monkeypatch.delenv('HERMES_WEBUI_PROFILE_COOKIE_NAME', raising=False)
279+
monkeypatch.setenv('WEBUI_PROFILE_COOKIE_NAME', 'hermes_profile_legacy')
280+
monkeypatch.setattr(helpers, '_legacy_profile_cookie_warned', False)
281+
with caplog.at_level(logging.WARNING, logger='api.helpers'):
282+
for _ in range(3):
283+
assert helpers.get_profile_cookie_name() == 'hermes_profile_legacy'
284+
warned = [r for r in caplog.records if 'deprecated' in r.getMessage()]
285+
assert len(warned) == 1
286+
287+
233288
# ── 2. Thread-local request context ──────────────────────────────────────────
234289

235290
class TestThreadLocalProfileContext:

0 commit comments

Comments
 (0)