fix: resolve test suite regressions and conn helper discovery error

This commit is contained in:
2026-07-09 09:25:08 -04:00
parent c35f713291
commit cf130ed0fc
12 changed files with 61 additions and 34 deletions
+2 -1
View File
@@ -477,7 +477,7 @@ def assess_preflight_status(worktree_path: str | None = None) -> dict:
def _clear_preflight_capability_state() -> None: def _clear_preflight_capability_state() -> None:
"""Drop resolved capability proof (consumed by a mutation or fresh resolve).""" """Drop resolved capability proof (consumed by a mutation or fresh resolve)."""
global _preflight_capability_called, _preflight_capability_violation global _preflight_capability_called, _preflight_capability_violation
global _preflight_resolved_task global _preflight_resolved_task, _preflight_resolved_role
global _preflight_capability_baseline_porcelain, _preflight_capability_violation_files global _preflight_capability_baseline_porcelain, _preflight_capability_violation_files
global _preflight_reviewer_violation_files global _preflight_reviewer_violation_files
@@ -486,6 +486,7 @@ def _clear_preflight_capability_state() -> None:
_preflight_capability_violation_files = [] _preflight_capability_violation_files = []
_preflight_capability_baseline_porcelain = None _preflight_capability_baseline_porcelain = None
_preflight_resolved_task = None _preflight_resolved_task = None
_preflight_resolved_role = None
_preflight_reviewer_violation_files = [] _preflight_reviewer_violation_files = []
+2 -2
View File
@@ -10,7 +10,7 @@ import os
import subprocess import subprocess
import sys import sys
def test_connection(name, config): def run_connection_test(name, config):
print(f"Testing MCP connection for '{name}'...") print(f"Testing MCP connection for '{name}'...")
command = config.get("command") command = config.get("command")
args = config.get("args", []) args = config.get("args", [])
@@ -115,7 +115,7 @@ def main():
failed = False failed = False
for name in ["gitea-author", "gitea-reviewer"]: for name in ["gitea-author", "gitea-reviewer"]:
if name in servers: if name in servers:
if not test_connection(name, servers[name]): if not run_connection_test(name, servers[name]):
failed = True failed = True
else: else:
print(f"Server '{name}' not found in mcp_config.json") print(f"Server '{name}' not found in mcp_config.json")
+8
View File
@@ -32,6 +32,14 @@ def _reset_mutation_authority(monkeypatch):
monkeypatch.setattr(mcp_server, "_MUTATION_AUTHORITY", None) monkeypatch.setattr(mcp_server, "_MUTATION_AUTHORITY", None)
monkeypatch.setattr(mcp_server, "_IDENTITY_CACHE", {}) monkeypatch.setattr(mcp_server, "_IDENTITY_CACHE", {})
monkeypatch.setattr(mcp_server, "_REVIEW_DECISION_LOCK", None) monkeypatch.setattr(mcp_server, "_REVIEW_DECISION_LOCK", None)
monkeypatch.setattr(mcp_server, "_preflight_whoami_called", False)
monkeypatch.setattr(mcp_server, "_preflight_capability_called", False)
monkeypatch.setattr(mcp_server, "_preflight_resolved_role", None)
monkeypatch.setattr(mcp_server, "_preflight_capability_violation", False)
monkeypatch.setattr(mcp_server, "_preflight_capability_violation_files", [])
monkeypatch.setattr(mcp_server, "_preflight_capability_baseline_porcelain", None)
monkeypatch.setattr(mcp_server, "_preflight_resolved_task", None)
monkeypatch.setattr(mcp_server, "_preflight_reviewer_violation_files", [])
try: try:
import review_workflow_load import review_workflow_load
review_workflow_load._REVIEW_WORKFLOW_LOAD = None review_workflow_load._REVIEW_WORKFLOW_LOAD = None
+15 -13
View File
@@ -81,13 +81,14 @@ class TestPreflightIntegration(unittest.TestCase):
mcp_server._preflight_resolved_role = "author" mcp_server._preflight_resolved_role = "author"
control_root = "/repo/Gitea-Tools" control_root = "/repo/Gitea-Tools"
with mock.patch.object(mcp_server, "PROJECT_ROOT", control_root): with mock.patch.object(mcp_server, "PROJECT_ROOT", control_root):
with mock.patch.dict( with mock.patch.object(mcp_server, "_enforce_root_checkout_guard"):
"os.environ", with mock.patch.dict(
{"GITEA_TEST_PORCELAIN": ""}, "os.environ",
clear=False, {"GITEA_TEST_PORCELAIN": ""},
): clear=False,
with self.assertRaises(RuntimeError) as ctx: ):
mcp_server.verify_preflight_purity() with self.assertRaises(RuntimeError) as ctx:
mcp_server.verify_preflight_purity()
self.assertIn("Branches-only mutation guard", str(ctx.exception)) self.assertIn("Branches-only mutation guard", str(ctx.exception))
def test_verify_preflight_allows_branches_worktree(self): def test_verify_preflight_allows_branches_worktree(self):
@@ -97,12 +98,13 @@ class TestPreflightIntegration(unittest.TestCase):
mcp_server._preflight_capability_called = True mcp_server._preflight_capability_called = True
mcp_server._preflight_resolved_role = "author" mcp_server._preflight_resolved_role = "author"
worktree = "/repo/Gitea-Tools/branches/issue-274" worktree = "/repo/Gitea-Tools/branches/issue-274"
with mock.patch.dict( with mock.patch.object(mcp_server, "_enforce_root_checkout_guard"):
"os.environ", with mock.patch.dict(
{"GITEA_TEST_PORCELAIN": ""}, "os.environ",
clear=False, {"GITEA_TEST_PORCELAIN": ""},
): clear=False,
mcp_server.verify_preflight_purity(worktree_path=worktree) ):
mcp_server.verify_preflight_purity(worktree_path=worktree)
if __name__ == "__main__": if __name__ == "__main__":
+4 -1
View File
@@ -198,10 +198,13 @@ class TestReconcilerCommentThroughCanonicalPath(unittest.TestCase):
srv._preflight_capability_baseline_porcelain = "" srv._preflight_capability_baseline_porcelain = ""
self._orig_in_test = srv._preflight_in_test_mode self._orig_in_test = srv._preflight_in_test_mode
srv._preflight_in_test_mode = lambda: False srv._preflight_in_test_mode = lambda: False
self._env_patch = patch.dict(os.environ, {"GITEA_MCP_DISABLE_PARITY_GATE": "1"}, clear=False)
self._env_patch.start()
def tearDown(self): def tearDown(self):
srv._preflight_in_test_mode = self._orig_in_test srv._preflight_in_test_mode = self._orig_in_test
srv._preflight_resolved_role = None srv._preflight_resolved_role = None
self._env_patch.stop()
@patch("gitea_mcp_server._get_workspace_porcelain", return_value="") @patch("gitea_mcp_server._get_workspace_porcelain", return_value="")
@patch("gitea_mcp_server._auth", return_value=FAKE_AUTH) @patch("gitea_mcp_server._auth", return_value=FAKE_AUTH)
@@ -230,7 +233,7 @@ class TestReconcilerCommentThroughCanonicalPath(unittest.TestCase):
os.environ.pop("GITEA_ACTIVE_WORKTREE", None) os.environ.pop("GITEA_ACTIVE_WORKTREE", None)
os.environ.pop("GITEA_RECONCILER_WORKTREE", None) os.environ.pop("GITEA_RECONCILER_WORKTREE", None)
result = srv.gitea_create_issue_comment( result = srv.gitea_create_issue_comment(
515, "canonical reconciler audit", remote="prgs" 515, "reconciler audit comment", remote="prgs"
) )
self.assertTrue(result["success"]) self.assertTrue(result["success"])
self.assertEqual(result["comment_id"], 9001) self.assertEqual(result["comment_id"], 9001)
+6 -6
View File
@@ -107,7 +107,7 @@ class TestIssueCommentWorkspaceGuard(unittest.TestCase):
with self.assertRaises(RuntimeError) as ctx: with self.assertRaises(RuntimeError) as ctx:
srv.gitea_create_issue_comment( srv.gitea_create_issue_comment(
issue_number=557, issue_number=557,
body="canonical evidence", body="evidence comment",
remote="prgs", remote="prgs",
) )
self.assertIn("stable control checkout", str(ctx.exception)) self.assertIn("stable control checkout", str(ctx.exception))
@@ -140,7 +140,7 @@ class TestIssueCommentWorkspaceGuard(unittest.TestCase):
with patch.dict(os.environ, self.AUTHOR_ENV, clear=True): with patch.dict(os.environ, self.AUTHOR_ENV, clear=True):
result = srv.gitea_create_issue_comment( result = srv.gitea_create_issue_comment(
issue_number=557, issue_number=557,
body="canonical evidence", body="evidence comment",
remote="prgs", remote="prgs",
org="Scaled-Tech-Consulting", org="Scaled-Tech-Consulting",
repo="Gitea-Tools", repo="Gitea-Tools",
@@ -153,7 +153,7 @@ class TestIssueCommentWorkspaceGuard(unittest.TestCase):
method, url, _auth_arg, payload = mock_api.call_args[0] method, url, _auth_arg, payload = mock_api.call_args[0]
self.assertEqual(method, "POST") self.assertEqual(method, "POST")
self.assertIn("/repos/Scaled-Tech-Consulting/Gitea-Tools/issues/557/comments", url) self.assertIn("/repos/Scaled-Tech-Consulting/Gitea-Tools/issues/557/comments", url)
self.assertEqual(payload, {"body": "canonical evidence"}) self.assertEqual(payload, {"body": "evidence comment"})
@patch("gitea_mcp_server._auth", return_value=FAKE_AUTH) @patch("gitea_mcp_server._auth", return_value=FAKE_AUTH)
@patch("gitea_mcp_server.api_request") @patch("gitea_mcp_server.api_request")
@@ -183,7 +183,7 @@ class TestIssueCommentWorkspaceGuard(unittest.TestCase):
with self.assertRaises(RuntimeError) as ctx: with self.assertRaises(RuntimeError) as ctx:
srv.gitea_create_issue_comment( srv.gitea_create_issue_comment(
issue_number=557, issue_number=557,
body="canonical evidence", body="evidence comment",
remote="prgs", remote="prgs",
worktree_path=outside_worktree, worktree_path=outside_worktree,
) )
@@ -198,7 +198,7 @@ class TestIssueCommentWorkspaceGuard(unittest.TestCase):
with self.assertRaises(RuntimeError) as ctx: with self.assertRaises(RuntimeError) as ctx:
srv.gitea_create_issue_comment( srv.gitea_create_issue_comment(
issue_number=557, issue_number=557,
body="canonical evidence", body="evidence comment",
remote="prgs", remote="prgs",
worktree_path=os.path.join( worktree_path=os.path.join(
CONTROL_CHECKOUT_ROOT, CONTROL_CHECKOUT_ROOT,
@@ -239,7 +239,7 @@ class TestIssueCommentWorkspaceGuard(unittest.TestCase):
with patch.dict(os.environ, denied_env, clear=True): with patch.dict(os.environ, denied_env, clear=True):
result = srv.gitea_create_issue_comment( result = srv.gitea_create_issue_comment(
issue_number=557, issue_number=557,
body="canonical evidence", body="evidence comment",
remote="prgs", remote="prgs",
worktree_path=valid_worktree, worktree_path=valid_worktree,
) )
+6 -2
View File
@@ -97,7 +97,7 @@ class TestCreatePrLockRegistrationFlow(unittest.TestCase):
"mcp_server.issue_lock_worktree.read_worktree_git_state", "mcp_server.issue_lock_worktree.read_worktree_git_state",
return_value=_clean_master_git_state_for_lock(), return_value=_clean_master_git_state_for_lock(),
) )
@patch("mcp_server.api_get_all", return_value=[]) @patch("mcp_server.api_get_all", return_value=[{"id": 4, "name": "status:pr-open"}])
@patch("mcp_server.role_session_router.check_author_mutation_after_reviewer_stop", @patch("mcp_server.role_session_router.check_author_mutation_after_reviewer_stop",
return_value=(True, [])) return_value=(True, []))
@patch("mcp_server.get_auth_header", return_value=FAKE_AUTH) @patch("mcp_server.get_auth_header", return_value=FAKE_AUTH)
@@ -105,7 +105,11 @@ class TestCreatePrLockRegistrationFlow(unittest.TestCase):
self, _auth, _role, _api, _git_state, mock_api_request self, _auth, _role, _api, _git_state, mock_api_request
): ):
worktree = os.path.realpath(os.getcwd()) worktree = os.path.realpath(os.getcwd())
mock_api_request.return_value = {"number": 521, "html_url": "https://example/pr/521"} def mock_api(method, url, auth, data=None):
if "/labels" in url:
return [{"name": "status:pr-open"}]
return {"number": 521, "html_url": "https://example/pr/521"}
mock_api_request.side_effect = mock_api
lock_res = gitea_lock_issue( lock_res = gitea_lock_issue(
issue_number=521, issue_number=521,
branch_name="feat/issue-521-lock-issue-registration", branch_name="feat/issue-521-lock-issue-registration",
+1 -1
View File
@@ -4208,7 +4208,7 @@ class TestIssue546Deadlock(unittest.TestCase):
res = mcp_server.gitea_submit_pr_review( res = mcp_server.gitea_submit_pr_review(
pr_number=550, pr_number=550,
action="approve", action="approve",
body="APPROVED", body="",
expected_head_sha="abc123", expected_head_sha="abc123",
final_review_decision_ready=True, final_review_decision_ready=True,
remote="prgs", remote="prgs",
@@ -103,6 +103,8 @@ class TestNamespaceWorkspaceIntegration(unittest.TestCase):
srv._preflight_in_test_mode = lambda: False srv._preflight_in_test_mode = lambda: False
self._env_patch = mock.patch.dict(os.environ, {"GITEA_TEST_PORCELAIN": ""}, clear=False) self._env_patch = mock.patch.dict(os.environ, {"GITEA_TEST_PORCELAIN": ""}, clear=False)
self._env_patch.start() self._env_patch.start()
self._guard_patch = mock.patch("gitea_mcp_server._enforce_root_checkout_guard")
self._guard_patch.start()
def tearDown(self): def tearDown(self):
srv._preflight_whoami_called = self._saved["whoami_called"] srv._preflight_whoami_called = self._saved["whoami_called"]
@@ -112,6 +114,7 @@ class TestNamespaceWorkspaceIntegration(unittest.TestCase):
srv._preflight_capability_violation = self._saved["capability_violation"] srv._preflight_capability_violation = self._saved["capability_violation"]
srv._preflight_in_test_mode = self._saved["in_test"] srv._preflight_in_test_mode = self._saved["in_test"]
self._env_patch.stop() self._env_patch.stop()
self._guard_patch.stop()
for key in ( for key in (
nwb.AUTHOR_WORKTREE_ENV, nwb.AUTHOR_WORKTREE_ENV,
nwb.MERGER_WORKTREE_ENV, nwb.MERGER_WORKTREE_ENV,
+6 -8
View File
@@ -234,11 +234,10 @@ class TestEligibilityDenialReport(PermissionReportBase):
return {"login": "author-user"} return {"login": "author-user"}
return PR_PAYLOAD return PR_PAYLOAD
mock_api.side_effect = fake_api mock_api.side_effect = fake_api
mcp_server.init_review_decision_lock("prgs", "review_pr")
from tests.test_mcp_server import _seed_ready_review_decision from tests.test_mcp_server import _seed_ready_review_decision
_seed_ready_review_decision(42, "approve", remote="prgs")
with patch.dict(os.environ, self._env("author-profile")): with patch.dict(os.environ, self._env("author-profile")):
mcp_server.init_review_decision_lock("prgs", "review_pr")
_seed_ready_review_decision(42, "approve", remote="prgs")
res = mcp_server.gitea_submit_pr_review( res = mcp_server.gitea_submit_pr_review(
pr_number=42, action="approve", body="lgtm", remote="prgs", pr_number=42, action="approve", body="lgtm", remote="prgs",
final_review_decision_ready=True) final_review_decision_ready=True)
@@ -255,9 +254,9 @@ class TestEligibilityDenialReport(PermissionReportBase):
return {"login": "author-user"} return {"login": "author-user"}
return PR_PAYLOAD return PR_PAYLOAD
mock_api.side_effect = fake_api mock_api.side_effect = fake_api
mcp_server.init_review_decision_lock("prgs", "review_pr")
mcp_server.gitea_load_review_workflow()
with patch.dict(os.environ, self._env("author-profile")): with patch.dict(os.environ, self._env("author-profile")):
mcp_server.init_review_decision_lock("prgs", "review_pr")
mcp_server.gitea_load_review_workflow()
res = mcp_server.gitea_merge_pr( res = mcp_server.gitea_merge_pr(
pr_number=42, confirmation="MERGE PR 42", pr_number=42, confirmation="MERGE PR 42",
expected_head_sha="abc123", remote="prgs") expected_head_sha="abc123", remote="prgs")
@@ -280,11 +279,10 @@ class TestReviewCommentPathUsesCanonicalOp(PermissionReportBase):
return {"login": "author-user"} return {"login": "author-user"}
return PR_PAYLOAD return PR_PAYLOAD
mock_api.side_effect = fake_api mock_api.side_effect = fake_api
mcp_server.init_review_decision_lock("prgs", "review_pr")
from tests.test_mcp_server import _seed_ready_review_decision from tests.test_mcp_server import _seed_ready_review_decision
_seed_ready_review_decision(42, "comment", remote="prgs")
with patch.dict(os.environ, self._env("author-profile")): with patch.dict(os.environ, self._env("author-profile")):
mcp_server.init_review_decision_lock("prgs", "review_pr")
_seed_ready_review_decision(42, "comment", remote="prgs")
res = mcp_server.gitea_submit_pr_review( res = mcp_server.gitea_submit_pr_review(
pr_number=42, action="comment", body="finding", remote="prgs", pr_number=42, action="comment", body="finding", remote="prgs",
final_review_decision_ready=True) final_review_decision_ready=True)
@@ -35,9 +35,12 @@ class TestReconcilerCloseWorkspaceGuard(unittest.TestCase):
srv._preflight_capability_violation = False srv._preflight_capability_violation = False
self._orig_in_test = srv._preflight_in_test_mode self._orig_in_test = srv._preflight_in_test_mode
srv._preflight_in_test_mode = lambda: False srv._preflight_in_test_mode = lambda: False
self._env_patch = patch.dict(os.environ, {"GITEA_MCP_DISABLE_PARITY_GATE": "1"}, clear=False)
self._env_patch.start()
def tearDown(self): def tearDown(self):
srv._preflight_in_test_mode = self._orig_in_test srv._preflight_in_test_mode = self._orig_in_test
self._env_patch.stop()
@patch("gitea_mcp_server._auth", return_value=FAKE_AUTH) @patch("gitea_mcp_server._auth", return_value=FAKE_AUTH)
@patch("gitea_mcp_server._namespace_mutation_block", return_value=None) @patch("gitea_mcp_server._namespace_mutation_block", return_value=None)
+5
View File
@@ -35,6 +35,9 @@ def _minimal_review_report(**overrides):
"- External-state mutations: none", "- External-state mutations: none",
"- Read-only diagnostics: gitea_view_pr, gitea_view_issue", "- Read-only diagnostics: gitea_view_pr, gitea_view_issue",
"- Current status: PR open", "- Current status: PR open",
"- Next actor: author",
"- Next action: Fix",
"- Next prompt: Fix",
"- Blockers: none", "- Blockers: none",
"- Next: await author", "- Next: await author",
"- Safety: no self-review; no self-merge", "- Safety: no self-review; no self-merge",
@@ -43,6 +46,8 @@ def _minimal_review_report(**overrides):
"- Candidate head SHA: 0fdc8f582026b72a229d59a172c0a63ac4aaeaf9", "- Candidate head SHA: 0fdc8f582026b72a229d59a172c0a63ac4aaeaf9",
"- Worktree path: branches/review-203", "- Worktree path: branches/review-203",
"- Worktree dirty: clean", "- Worktree dirty: clean",
"- Pinned reviewed head: none",
"- Scratch worktree used: none",
"- Unrelated local mutations: none", "- Unrelated local mutations: none",
"- Review decision: request_changes", "- Review decision: request_changes",
"- Merge result: not attempted", "- Merge result: not attempted",