fix(#5588): reset memoized password-hash cache around every test (isolation flake)
tests/test_issue803.py::TestProfileCookieHelpers failed when run after tests/test_session_static_assets.py (passed in isolation). Root cause: api.auth.get_password_hash() memoizes the resolved hash process-wide (_AUTH_HASH_CACHE / _AUTH_HASH_COMPUTED) and is NOT keyed on the HERMES_WEBUI_PASSWORD env var. test_session_static_auth_exemption sets that env var + populates the cache; monkeypatch pops the env on teardown but the cache stays populated, so is_auth_enabled() reads stale True and build_profile_cookie raises "requires a request handler when auth is enabled". Fix: an autouse conftest fixture (_reset_password_hash_cache) that invalidates the cache before AND after every test — matching the existing _isolate_hermes_config_path / _restore_profile_home_globals autouse-reset convention. Fixes the whole class regardless of which test sets the password; no-op when auth is off. Adds a direct regression test (cache a password, pop env, assert auth reads disabled + build_profile_cookie doesn't raise). Paired-run repro now passes.
This commit is contained in:
1 parent
c922f179f7
commit
4c9690bf59
2 files changed
+50
No files matched your search
@@ -190,6 +190,32 @@ def _isolate_hermes_config_path():
|
||||
os.environ['HERMES_CONFIG_PATH'] = isolated_config_path
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _reset_password_hash_cache():
|
||||
"""Reset the memoized password-hash cache around every test (#5588).
|
||||
|
||||
api.auth.get_password_hash() caches the resolved hash process-wide
|
||||
(_AUTH_HASH_CACHE / _AUTH_HASH_COMPUTED) for perf — it is NOT keyed on the
|
||||
HERMES_WEBUI_PASSWORD env var. A test that sets that env var (e.g.
|
||||
test_session_static_assets.test_session_static_auth_exemption) populates the
|
||||
cache with a real hash; monkeypatch pops the env var on teardown but the
|
||||
cache stays populated, so is_auth_enabled() reads stale True and later tests
|
||||
(e.g. test_issue803's profile-cookie helpers) fail with a spurious
|
||||
"requires a request handler when auth is enabled". Invalidate before AND
|
||||
after each test so neither a pre-existing cached value nor a value this test
|
||||
populates leaks across the isolation boundary. No-op when auth is off.
|
||||
"""
|
||||
try:
|
||||
from api.auth import _invalidate_password_hash_cache
|
||||
except Exception:
|
||||
_invalidate_password_hash_cache = None
|
||||
if _invalidate_password_hash_cache:
|
||||
_invalidate_password_hash_cache()
|
||||
yield
|
||||
if _invalidate_password_hash_cache:
|
||||
_invalidate_password_hash_cache()
|
||||
|
||||
|
||||
_MISSING = object() # sentinel: api.profiles module not loaded pre-test
|
||||
|
||||
|
||||
|
||||
@@ -34,6 +34,30 @@ class TestProfileCookieHelpers:
|
||||
assert 'SameSite=Lax' in s
|
||||
assert 'Path=/' in s
|
||||
|
||||
def test_build_profile_cookie_survives_stale_password_hash_cache(self, monkeypatch):
|
||||
"""#5588 regression: a prior test that set HERMES_WEBUI_PASSWORD populates
|
||||
api.auth's process-wide password-hash cache; if that cache leaks past the
|
||||
env-var teardown, is_auth_enabled() reads stale True and build_profile_cookie
|
||||
raises "requires a request handler when auth is enabled". Simulate the leak
|
||||
in-test: cache a password, pop the env, and confirm the memoized state does
|
||||
not make a no-handler build_profile_cookie raise. (The autouse
|
||||
_reset_password_hash_cache fixture is what keeps this from leaking across
|
||||
real test files.)"""
|
||||
import api.auth as auth
|
||||
from api.helpers import build_profile_cookie
|
||||
# Populate the cache as if an auth-enabled test just ran.
|
||||
monkeypatch.setenv("HERMES_WEBUI_PASSWORD", "leak-check")
|
||||
auth._invalidate_password_hash_cache()
|
||||
assert auth.is_auth_enabled() is True # cache now holds a hash
|
||||
# Env goes away (as monkeypatch would on teardown) but reset the cache the
|
||||
# way the autouse fixture does — auth must read as disabled again.
|
||||
monkeypatch.delenv("HERMES_WEBUI_PASSWORD", raising=False)
|
||||
auth._invalidate_password_hash_cache()
|
||||
assert auth.is_auth_enabled() is False
|
||||
# And the no-handler cookie build must not raise.
|
||||
s = build_profile_cookie('alice')
|
||||
assert 'hermes_profile=alice' in s
|
||||
|
||||
def test_build_profile_cookie_default_persists(self):
|
||||
from api.helpers import build_profile_cookie
|
||||
s = build_profile_cookie('default')
|
||||
|
||||
Reference in new issue
Block a user