Merge pull request 'feat(#496): enforce canonical state comment validation before posting' (#497) from feat/issue-496-canonical-comment-validator into master

This commit was merged in pull request #497.
This commit is contained in:
2026-07-09 07:57:47 -05:00
7 changed files with 855 additions and 0 deletions
+61
View File
@@ -838,6 +838,7 @@ import master_parity_gate # noqa: E402
# Read-only operations are never blocked by staleness.
_STARTUP_PARITY = master_parity_gate.capture_startup_parity(PROJECT_ROOT)
import worktree_cleanup_audit # noqa: E402
import canonical_comment_validator as ccv # noqa: E402
# Keyed issue-lock storage (#443): per remote/org/repo/issue files under
@@ -3492,6 +3493,13 @@ def _evaluate_pr_review_submission(
result["pr_work_lease"] = lease_block
return result
if (body or "").strip():
gate = _canonical_comment_gate(body, context="pr_review")
if gate["blocked"]:
reasons.extend(gate["reasons"])
result["canonical_comment_validation"] = gate["canonical_comment_validation"]
return result
result["would_perform"] = True
if not live:
reasons.append(
@@ -5469,6 +5477,12 @@ def gitea_reconcile_already_landed_pr(
"gitea.pr.comment"
)
return result
gate = _canonical_comment_gate(comment_body)
if gate["blocked"]:
result["success"] = False
result["reasons"].extend(gate["reasons"])
result["canonical_comment_validation"] = gate["canonical_comment_validation"]
return result
comment_url = f"{base}/issues/{pr_number}/comments"
with _audited(
"comment_pr",
@@ -6732,6 +6746,15 @@ def gitea_create_issue_comment(
blocked["permission_report"] = _permission_block_report(
"gitea.issue.comment")
return blocked
canon_gate = _canonical_comment_gate(body, context="issue_comment")
if canon_gate["blocked"]:
return {
"success": False,
"performed": False,
"issue_number": issue_number,
"reasons": canon_gate["reasons"],
"canonical_comment_validation": canon_gate["canonical_comment_validation"],
}
h, o, r = _resolve(remote, host, org, repo)
auth = _auth(h)
api = f"{repo_api_url(h, o, r)}/issues/{issue_number}/comments"
@@ -8316,6 +8339,34 @@ def gitea_audit_config() -> dict:
return report
def _canonical_comment_gate(
body: str,
*,
context: str | None = None,
force_workflow: bool = False,
) -> dict:
"""Fail-closed canonical state validation before comment/review POST (#496)."""
assessment = ccv.assess_canonical_comment(
body,
context=context,
force_workflow=force_workflow,
)
if assessment.get("allowed"):
return {
"blocked": False,
"canonical_comment_validation": assessment,
"reasons": [],
}
correction = (assessment.get("correction_message") or "").strip()
return {
"blocked": True,
"canonical_comment_validation": assessment,
"reasons": [
correction or "canonical comment validation failed (fail closed before posting)"
],
}
def _post_structured_issue_comment(
*,
issue_number: int,
@@ -8325,8 +8376,18 @@ def _post_structured_issue_comment(
org: str | None,
repo: str | None,
audit_op: str = "create_issue_comment",
comment_context: str | None = None,
) -> dict:
"""Post an issue-thread comment after permission gates already passed."""
gate = _canonical_comment_gate(body, context=comment_context)
if gate["blocked"]:
return {
"success": False,
"performed": False,
"issue_number": issue_number,
"reasons": gate["reasons"],
"canonical_comment_validation": gate["canonical_comment_validation"],
}
h, o, r = _resolve(remote, host, org, repo)
auth = _auth(h)
api = f"{repo_api_url(h, o, r)}/issues/{issue_number}/comments"