feat(webhook): is_repo_enabled reads .pr-review.json:enabled
This commit is contained in:
+28
-1
@@ -34,14 +34,16 @@ Env:
|
||||
(optional) request-body cap, default 10 MiB
|
||||
"""
|
||||
|
||||
import base64
|
||||
import hashlib
|
||||
import hmac
|
||||
import json
|
||||
import os
|
||||
import threading
|
||||
import urllib.parse
|
||||
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
||||
|
||||
from ai_review import review_pr
|
||||
from ai_review import gitea_get, review_pr
|
||||
|
||||
try:
|
||||
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)
|
||||
|
||||
|
||||
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:
|
||||
if not WEBHOOK_SECRET:
|
||||
return False # refuse to run without a configured secret
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
"""Unit tests for the webhook receiver's gating, dedupe and limits. No network."""
|
||||
import base64
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
@@ -134,3 +135,35 @@ def test_missing_label_is_ignored(monkeypatch):
|
||||
def test_review_slots_bound_matches_config():
|
||||
assert ws.MAX_CONCURRENT >= 1
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user