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
|
(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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user