fix(security): re-resolve checkpoint/sticker-cache paths per call
tools/checkpoint_manager.py's CHECKPOINT_BASE and gateway/sticker_cache.py's CACHE_PATH are resolved once at import time via get_hermes_home(), which is a context-local ContextVar under the multiplexed gateway (multiple profiles sharing one process). Freezing the path at import time pins every later checkpoint/cache read-write to whichever profile's HERMES_HOME was active when the module was first imported -- the same bug class already fixed for cache dirs, skills_hub, rich_sent_store, and (this session) the OAuth/auth.json/ sessions.json paths. CheckpointManager is "owned by AIAgent" per-instance, but its methods read the frozen module constant directly instead of taking the store root from the instance, so a profile's CheckpointManager can read/write code-edit checkpoints into a different profile's store. Add a per-call resolver for each path, following the established "respect an existing test monkeypatch of the constant, otherwise re-resolve through get_hermes_home()" pattern so the extensive existing test seams in tests/tools/test_checkpoint_manager.py and tests/gateway/test_sticker_cache.py keep working unmodified. (cherry picked from commit 03ae075d969094cb584e6ab38d2a773d15ff875c) (cherry picked from commit b850c4b18e2ae2158a97c6cb87bd2057918b8170)
This commit is contained in:
@@ -156,6 +156,47 @@ class TestGatewayHooksDirResolution:
|
||||
assert "only-in-b" in b_hooks
|
||||
|
||||
|
||||
class TestCheckpointManagerPathResolution:
|
||||
"""tools/checkpoint_manager.py's checkpoint store root must honor the
|
||||
active profile — otherwise one profile's CheckpointManager instance can
|
||||
read/write code-edit checkpoints into a different profile's store under
|
||||
the multiplexed gateway."""
|
||||
|
||||
def test_checkpoint_base_follows_override(self, two_profiles):
|
||||
prof_a, prof_b = two_profiles
|
||||
import tools.checkpoint_manager as cm
|
||||
|
||||
a_seen = _under_override(prof_a, lambda: cm._resolve_checkpoint_base())
|
||||
b_seen = _under_override(prof_b, lambda: cm._resolve_checkpoint_base())
|
||||
|
||||
assert a_seen == prof_a / "checkpoints"
|
||||
assert b_seen == prof_b / "checkpoints"
|
||||
assert a_seen != b_seen
|
||||
|
||||
def test_store_path_follows_override(self, two_profiles):
|
||||
prof_a, prof_b = two_profiles
|
||||
import tools.checkpoint_manager as cm
|
||||
|
||||
b_seen = _under_override(prof_b, lambda: cm._store_path())
|
||||
assert b_seen == prof_b / "checkpoints" / "store"
|
||||
|
||||
|
||||
class TestStickerCachePathResolution:
|
||||
"""gateway/sticker_cache.py's cache file must honor the active profile —
|
||||
otherwise one profile's Telegram sticker-description cache leaks into a
|
||||
different profile's under the multiplexed gateway."""
|
||||
|
||||
def test_cache_path_follows_override(self, two_profiles):
|
||||
prof_a, prof_b = two_profiles
|
||||
import gateway.sticker_cache as sc
|
||||
|
||||
a_seen = _under_override(prof_a, lambda: sc._resolve_cache_path())
|
||||
b_seen = _under_override(prof_b, lambda: sc._resolve_cache_path())
|
||||
|
||||
assert a_seen == prof_a / "sticker_cache.json"
|
||||
assert b_seen == prof_b / "sticker_cache.json"
|
||||
assert a_seen != b_seen
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# M2 — thread / executor context propagation
|
||||
|
||||
Reference in New Issue
Block a user