fix: isolate review-mutation ledger from host session-state (#590)
Tests that call patch.dict(os.environ, clear=True) dropped GITEA_MCP_SESSION_STATE_DIR and re-adopted the operator host cache under ~/.cache/gitea-tools/session-state. A residual terminal request_changes mutation then tripped the #332 hard-stop before test_unknown_profile_blocks could assert the empty-profile gate. - Pin mcp_session_state.default_state_dir / DEFAULT_STATE_DIR to a per-test temp dir in conftest (still honors an explicit env override) - Clear the decision lock at the start of each TestMergePR test - Add regression coverage for env-clear isolation Closes #590
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
"""Regression: durable session-state isolation survives env clears (#590)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
import mcp_session_state
|
||||
|
||||
|
||||
def test_default_state_dir_survives_env_clear():
|
||||
"""conftest pins default_state_dir so clear=True cannot hit host cache."""
|
||||
isolated = os.environ.get("GITEA_MCP_SESSION_STATE_DIR")
|
||||
assert isolated, "conftest must set GITEA_MCP_SESSION_STATE_DIR"
|
||||
host_cache = Path.home() / ".cache" / "gitea-tools" / "session-state"
|
||||
with patch.dict(os.environ, {}, clear=True):
|
||||
assert os.environ.get("GITEA_MCP_SESSION_STATE_DIR") is None
|
||||
resolved = mcp_session_state.default_state_dir()
|
||||
assert resolved == isolated
|
||||
assert Path(resolved).resolve() != host_cache.resolve()
|
||||
|
||||
|
||||
def test_decision_lock_save_load_stays_in_isolated_dir():
|
||||
"""Review-mutation ledger files land only under the per-test state dir."""
|
||||
isolated = os.environ.get("GITEA_MCP_SESSION_STATE_DIR")
|
||||
assert isolated
|
||||
with patch.dict(os.environ, {}, clear=True):
|
||||
saved = mcp_session_state.save_state(
|
||||
kind=mcp_session_state.KIND_DECISION_LOCK,
|
||||
profile_identity="gitea-default",
|
||||
payload={
|
||||
"live_mutations": [
|
||||
{"pr_number": 1, "action": "request_changes"}
|
||||
],
|
||||
},
|
||||
)
|
||||
assert saved is not None
|
||||
path = mcp_session_state.state_file_path(
|
||||
kind=mcp_session_state.KIND_DECISION_LOCK,
|
||||
profile_identity="gitea-default",
|
||||
)
|
||||
assert path.startswith(isolated + os.sep) or path.startswith(
|
||||
isolated + "/"
|
||||
)
|
||||
loaded = mcp_session_state.load_state(
|
||||
kind=mcp_session_state.KIND_DECISION_LOCK,
|
||||
profile_identity="gitea-default",
|
||||
)
|
||||
assert loaded is not None
|
||||
assert loaded.get("live_mutations")
|
||||
host_path = (
|
||||
Path.home()
|
||||
/ ".cache"
|
||||
/ "gitea-tools"
|
||||
/ "session-state"
|
||||
/ "review_decision_lock-gitea-default.json"
|
||||
)
|
||||
# Host file may exist from operator use; this write must not refresh it.
|
||||
# Prove our isolated file is distinct and present.
|
||||
assert Path(path).is_file()
|
||||
assert Path(path).resolve() != host_path.resolve()
|
||||
Reference in New Issue
Block a user