"""Controller quarantine of contaminated formal reviews (#695). Quarantine records are durable under the MCP session-state root and are only writable when the caller holds a **native** MCP transport runtime. Untrusted local scripts that import this module cannot establish a valid quarantine (writes fail closed). Live server-side gates (eligibility, merge, feedback) honor quarantine by review_id + PR + head. Forensic evidence (Gitea review objects, lease comments) is never deleted. """ from __future__ import annotations import json import os from datetime import datetime, timezone from typing import Any import mcp_daemon_guard import mcp_session_state KIND_QUARANTINE = "review_quarantine" CONFIRMATION_PREFIX = "QUARANTINE CONTAMINATED REVIEW" def _now() -> str: return datetime.now(timezone.utc).isoformat() def quarantine_state_path( *, remote: str, org: str, repo: str, pr_number: int, review_id: int, ) -> str: # Dedicated subdir under session state root (mode 0o700). root = os.path.join(mcp_session_state.default_state_dir(), "quarantine") os.makedirs(root, mode=0o700, exist_ok=True) # Explicit multi-segment key so remote/org/repo/pr/review cannot collide. segs = [ KIND_QUARANTINE, mcp_session_state._sanitize_segment(remote), mcp_session_state._sanitize_segment(org), mcp_session_state._sanitize_segment(repo), f"pr{int(pr_number)}", f"rev{int(review_id)}", ] return os.path.join(root, "-".join(segs) + ".json") def build_quarantine_record( *, remote: str, org: str, repo: str, pr_number: int, review_id: int, reviewed_head_sha: str, reason: str, actor_username: str | None, profile_name: str | None, incident_issue: int | None = None, forensic_comment_ids: list[int] | None = None, ) -> dict[str, Any]: provenance = mcp_daemon_guard.mutation_provenance_fields() return { "kind": KIND_QUARANTINE, "issue_ref": "#695", "remote": remote, "org": org, "repo": repo, "pr_number": int(pr_number), "review_id": int(review_id), "reviewed_head_sha": (reviewed_head_sha or "").strip().lower(), "reason": (reason or "").strip(), "actor_username": actor_username, "profile_name": profile_name, "incident_issue": incident_issue, "forensic_comment_ids": list(forensic_comment_ids or []), "created_at": _now(), "native_provenance": provenance, "merge_authorization": "void", "retain_forensic_evidence": True, } def assess_quarantine_write( *, confirmation: str, pr_number: int, review_id: int, reason: str, native_required: bool = True, ) -> dict[str, Any]: """Pure assessment of whether a quarantine write may proceed.""" reasons: list[str] = [] expected = f"{CONFIRMATION_PREFIX} {int(review_id)} PR {int(pr_number)}" if (confirmation or "").strip() != expected: reasons.append( f"confirmation must equal exactly '{expected}' (fail closed, #695)" ) if not (reason or "").strip(): reasons.append("quarantine reason is required (fail closed, #695)") if native_required and not mcp_daemon_guard.is_native_mcp_transport(): if not mcp_daemon_guard.is_pytest_runtime(): reasons.append( "quarantine write requires native MCP transport; untrusted " "local code cannot create quarantine records (#695)" ) return { "allowed": not reasons, "expected_confirmation": expected, "reasons": reasons, } def write_quarantine_record(record: dict[str, Any]) -> dict[str, Any]: """Persist quarantine record; fail closed outside native/pytest runtime.""" if not mcp_daemon_guard.is_native_mcp_transport(): if not mcp_daemon_guard.is_pytest_runtime(): raise mcp_daemon_guard.UnsanctionedRuntimeError( "quarantine write blocked: non-native runtime (#695)" ) path = quarantine_state_path( remote=str(record["remote"]), org=str(record["org"]), repo=str(record["repo"]), pr_number=int(record["pr_number"]), review_id=int(record["review_id"]), ) # Refuse overwriting with weaker provenance from untrusted caller by # requiring native fields present. if not (record.get("native_provenance") or {}).get("native_mcp_transport"): if not mcp_daemon_guard.is_pytest_runtime(): raise mcp_daemon_guard.UnsanctionedRuntimeError( "quarantine record missing native provenance (#695)" ) tmp = path + ".tmp" data = json.dumps(record, indent=2, sort_keys=True) with open(tmp, "w", encoding="utf-8") as fh: fh.write(data) fh.flush() os.fsync(fh.fileno()) os.replace(tmp, path) os.chmod(path, 0o600) return {"path": path, "written": True, "record": record} def load_quarantine_record( *, remote: str, org: str, repo: str, pr_number: int, review_id: int, ) -> dict[str, Any] | None: path = quarantine_state_path( remote=remote, org=org, repo=repo, pr_number=pr_number, review_id=review_id, ) if not os.path.isfile(path): return None try: with open(path, encoding="utf-8") as fh: data = json.load(fh) except (OSError, json.JSONDecodeError): return None if not isinstance(data, dict): return None return data def is_review_quarantined( *, remote: str, org: str, repo: str, pr_number: int, review_id: int | None, reviewed_head_sha: str | None = None, ) -> dict[str, Any]: """Whether a formal review is quarantined for merge authorization (#695).""" if review_id is None: return {"quarantined": False, "record": None, "reasons": []} rec = load_quarantine_record( remote=remote, org=org, repo=repo, pr_number=pr_number, review_id=int(review_id), ) if not rec: return {"quarantined": False, "record": None, "reasons": []} reasons = [ f"formal review_id {review_id} on PR #{pr_number} is quarantined " f"(#695; incident issue {rec.get('incident_issue')}); " "merge authorization is void; forensic evidence retained" ] want_head = (reviewed_head_sha or "").strip().lower() rec_head = (rec.get("reviewed_head_sha") or "").strip().lower() if want_head and rec_head and want_head != rec_head: # Still quarantined by review_id; note head mismatch for operators. reasons.append( f"quarantine head {rec_head[:12]}… differs from assessed head " f"{want_head[:12]}… (still void by review_id)" ) return {"quarantined": True, "record": rec, "reasons": reasons} def filter_approvals_for_merge( *, remote: str, org: str, repo: str, pr_number: int, current_head_sha: str | None, reviews: list[dict], ) -> dict[str, Any]: """Split reviews into merge-usable vs quarantined contaminated approvals.""" current = (current_head_sha or "").strip().lower() usable: list[dict] = [] quarantined: list[dict] = [] for rev in reviews or []: if not isinstance(rev, dict): continue verdict = (rev.get("verdict") or rev.get("state") or "").upper() if verdict not in {"APPROVED", "APPROVE"}: continue if rev.get("dismissed"): continue rid = rev.get("review_id") or rev.get("id") head = ( rev.get("reviewed_head_sha") or rev.get("commit_id") or rev.get("head_sha") or "" ).strip().lower() q = is_review_quarantined( remote=remote, org=org, repo=repo, pr_number=pr_number, review_id=int(rid) if rid is not None else None, reviewed_head_sha=head or current, ) entry = {**rev, "review_id": rid, "reviewed_head_sha": head} if q["quarantined"]: entry["quarantined"] = True entry["quarantine_reasons"] = q["reasons"] quarantined.append(entry) else: entry["quarantined"] = False usable.append(entry) usable_at_head = [ e for e in usable if current and (e.get("reviewed_head_sha") or "") == current ] return { "usable_approvals": usable, "usable_approvals_at_current_head": usable_at_head, "quarantined_approvals": quarantined, "approval_visible_for_merge": bool(usable_at_head), "has_quarantined_approval_at_head": any( current and (e.get("reviewed_head_sha") or "") == current for e in quarantined ), } def format_quarantine_audit_comment(record: dict[str, Any]) -> str: """Append-only forensic audit comment body (does not delete evidence).""" lines = [ "## Contaminated formal review quarantine (#695)", "", "Status: **QUARANTINED — merge authorization VOID**", "", f"- review_id: `{record.get('review_id')}`", f"- pr: `#{record.get('pr_number')}`", f"- reviewed_head_sha: `{record.get('reviewed_head_sha')}`", f"- actor: `{record.get('actor_username')}`", f"- profile: `{record.get('profile_name')}`", f"- incident_issue: `#{record.get('incident_issue')}`", f"- reason: {record.get('reason')}", f"- created_at: `{record.get('created_at')}`", f"- native_transport: " f"`{(record.get('native_provenance') or {}).get('native_mcp_transport')}`", f"- native_token_fingerprint: " f"`{(record.get('native_provenance') or {}).get('native_token_fingerprint')}`", f"- forensic_comment_ids retained: " f"`{record.get('forensic_comment_ids')}`", "", "This record does **not** delete Gitea reviews or historical comments. " "Fresh native-MCP re-review is required before merge.", ] return "\n".join(lines) def assess_untrusted_canonical_approval_claim(body: str) -> list[str]: """Reasons to reject canonical comments that claim approved/merge-ready. Used when the comment asserts approval without native review proof (#695 AC7). False "official workflow" claims that cite offline/import paths are always rejected even when a NATIVE_REVIEW_PROOF line is present. """ text = body or "" lower = text.lower() claims_approved = ( "state:\napproved" in lower or "state: approved" in lower or "who_is_next:\nmerger" in lower or "who_is_next: merger" in lower or "merge_ready: true" in lower or "merge_ready:\ntrue" in lower or "ready-to-merge" in lower ) if not claims_approved: return [] # Reject explicit offline/import "official workflow" spoofing (#695 AC9). offline_spoof = ( "offline_mcp" in lower or "offline import" in lower or "direct import" in lower or "import gitea_mcp_server" in lower or "run_quarantine.py" in lower or "offline_mcp_helper" in lower or "offline_mcp_runner" in lower ) has_proof = ( "NATIVE_REVIEW_PROOF:" in text or "native_review_proof:" in lower ) if offline_spoof: return [ "canonical approval claim cites offline/import/helper path; " "NATIVE_REVIEW_PROOF rejected (#695 AC7/AC9); stop after native " "MCP failure — do not construct offline mutation fallbacks" ] if has_proof: return [] return [ "canonical comment claims approved/merge-ready state without " "NATIVE_REVIEW_PROOF from a native MCP review mutation (#695 AC7); " "contaminated or untrusted approvals cannot certify merger handoff" ]