feat(webhook): is_repo_enabled reads .pr-review.json:enabled

This commit is contained in:
claude
2026-08-22 01:24:10 +00:00
parent 86352a3771
commit 2c7d4803f1
2 changed files with 61 additions and 1 deletions
+28 -1
View File
@@ -34,14 +34,16 @@ Env:
(optional) request-body cap, default 10 MiB (optional) request-body cap, default 10 MiB
""" """
import base64
import hashlib import hashlib
import hmac import hmac
import json import json
import os import os
import threading import threading
import urllib.parse
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from ai_review import review_pr from ai_review import gitea_get, review_pr
try: try:
import feedback_harvest # optional — absent in CI-step pod, present in import feedback_harvest # optional — absent in CI-step pod, present in
@@ -109,6 +111,31 @@ def _labels_have_ai_review(labels) -> bool:
return _labels_have(labels, AI_REVIEW_LABEL) return _labels_have(labels, AI_REVIEW_LABEL)
def is_repo_enabled(api: str, repo: str, ref: str, token: str) -> bool:
"""True iff `.pr-review.json` on `ref` has `"enabled": true`.
Reads from the given ref (typically the PR's base ref). False on any
failure: 404, parse error, missing file, missing `enabled`, wrong type.
The bool-coerce of `.get("enabled") is True` rejects the common
gotchas (`null`, `1`, `"yes"`, missing field all yield False).
"""
code, raw = gitea_get(
api, repo,
"contents/.pr-review.json?ref=" + urllib.parse.quote(ref, safe=""),
token,
)
if code != 200:
return False
try:
data = json.loads(raw)
content_b64 = data.get("content", "").replace("\n", "")
decoded = base64.b64decode(content_b64).decode("utf-8", errors="replace")
cfg = json.loads(decoded)
except (json.JSONDecodeError, ValueError):
return False
return isinstance(cfg, dict) and cfg.get("enabled") is True
def _verify_signature(raw_body: bytes, headers) -> bool: def _verify_signature(raw_body: bytes, headers) -> bool:
if not WEBHOOK_SECRET: if not WEBHOOK_SECRET:
return False # refuse to run without a configured secret return False # refuse to run without a configured secret
+33
View File
@@ -1,4 +1,5 @@
"""Unit tests for the webhook receiver's gating, dedupe and limits. No network.""" """Unit tests for the webhook receiver's gating, dedupe and limits. No network."""
import base64
import os import os
import sys import sys
import threading import threading
@@ -134,3 +135,35 @@ def test_missing_label_is_ignored(monkeypatch):
def test_review_slots_bound_matches_config(): def test_review_slots_bound_matches_config():
assert ws.MAX_CONCURRENT >= 1 assert ws.MAX_CONCURRENT >= 1
assert ws._review_slots._value <= ws.MAX_CONCURRENT assert ws._review_slots._value <= ws.MAX_CONCURRENT
# ---------------------------------------------------------------------------
# is_repo_enabled — reads `.pr-review.json` from the PR base ref and parses
# its `enabled` flag. False on any failure (404, parse error, missing field).
# ---------------------------------------------------------------------------
def test_is_repo_enabled_returns_false_when_404(monkeypatch):
monkeypatch.setattr(
"webhook_server.gitea_get",
lambda *a, **kw: (404, b'{"message":"not found"}'),
)
assert ws.is_repo_enabled("api", "owner/repo", "main", "tok") is False
def test_is_repo_enabled_returns_true_when_enabled(monkeypatch):
body = b'{"content":"' + base64.b64encode(b'{"enabled": true}').decode().encode() + b'"}'
monkeypatch.setattr("webhook_server.gitea_get", lambda *a, **kw: (200, body))
assert ws.is_repo_enabled("api", "owner/repo", "main", "tok") is True
def test_is_repo_enabled_returns_false_when_disabled(monkeypatch):
body = b'{"content":"' + base64.b64encode(b'{"enabled": false}').decode().encode() + b'"}'
monkeypatch.setattr("webhook_server.gitea_get", lambda *a, **kw: (200, body))
assert ws.is_repo_enabled("api", "owner/repo", "main", "tok") is False
def test_is_repo_enabled_returns_false_when_field_missing(monkeypatch):
body = b'{"content":"' + base64.b64encode(b'{}').decode().encode() + b'"}'
monkeypatch.setattr("webhook_server.gitea_get", lambda *a, **kw: (200, body))
assert ws.is_repo_enabled("api", "owner/repo", "main", "tok") is False