fix(gate-check-v3): defend against user=null in review JSON #1862

Merged
agent-dev-a merged 1 commits from fix/gate-check-v3-null-user-crash into main 2026-05-26 09:08:43 +00:00
2 changed files with 61 additions and 2 deletions
+9 -2
View File
@@ -264,11 +264,18 @@ def signal_2_reviews(pr_number: int, repo: str) -> dict:
blocking = []
for r in reviews:
if r.get("state") == "REQUEST_CHANGES" and not r.get("dismissed", False):
if (
r.get("state") == "REQUEST_CHANGES"
and not r.get("dismissed", False)
and r.get("official") is not False
):
login = (r.get("user") or {}).get("login", "")
if not login:
continue
blocking.append(
{
"review_id": r["id"],
"user": r["user"]["login"],
"user": login,
"commit_id": r.get("commit_id", ""),
"created_at": r.get("submitted_at") or r.get("created_at", ""),
}
+52
View File
@@ -119,3 +119,55 @@ def test_signal_1_null_user_in_review_does_not_crash(monkeypatch):
# Should not crash; the valid review from core-devops still satisfies engineers gate
assert result["verdict"] == "CLEAR"
assert result["results"]["core-devops"]["verdict"] == "APPROVED"
def test_signal_2_draft_request_changes_does_not_block(monkeypatch):
"""official=False REQUEST_CHANGES is a draft/pending review and must NOT
block the gate (matching review-check.sh post-#1818 official-filter)."""
mod = load_gate_check()
def fake_api_list(path):
if path == "/repos/molecule-ai/molecule-core/pulls/902/reviews":
return [
{
"id": 1,
"user": {"login": "agent-reviewer"},
"state": "REQUEST_CHANGES",
"official": False,
"dismissed": False,
"submitted_at": "2026-05-13T10:00:00Z",
}
]
raise AssertionError(f"unexpected api_list: {path}")
monkeypatch.setattr(mod, "api_list", fake_api_list)
result = mod.signal_2_reviews(902, "molecule-ai/molecule-core")
assert result["verdict"] == "CLEAR"
assert result["blocking_reviews"] == []
def test_signal_2_null_user_in_request_changes_does_not_crash(monkeypatch):
"""Regression: Gitea may return user=null on a REQUEST_CHANGES review.
signal_2_reviews must survive this without AttributeError."""
mod = load_gate_check()
def fake_api_list(path):
if path == "/repos/molecule-ai/molecule-core/pulls/903/reviews":
return [
{
"id": 1,
"user": None,
"state": "REQUEST_CHANGES",
"official": True,
"dismissed": False,
"submitted_at": "2026-05-13T10:00:00Z",
}
]
raise AssertionError(f"unexpected api_list: {path}")
monkeypatch.setattr(mod, "api_list", fake_api_list)
result = mod.signal_2_reviews(903, "molecule-ai/molecule-core")
assert result["verdict"] == "CLEAR"
assert result["blocking_reviews"] == []