Skip to content

Commit c05acbb

Browse files
andrewgazelkacodex
andauthored
ci: dedupe ai markers by publisher (#202)
## Summary - resolve the publishing token login before scanning AI review markers - dedupe existing markers from that publisher plus the legacy GitHub Actions bot identities - keep marker suppression limited to trusted publisher identities instead of arbitrary commenters ## Checks - `nix run nixpkgs#actionlint -- .github/workflows/ai-review-gate.yml` - `nix run .#lint` Refs #137 review feedback. --------- Co-authored-by: Codex <codex@openai.com>
1 parent 84bdb2d commit c05acbb

1 file changed

Lines changed: 44 additions & 7 deletions

File tree

.github/workflows/ai-review-gate.yml

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -382,8 +382,8 @@ jobs:
382382
SUMMARY_MARKER = f"<!-- ai-review-summary:{HEAD_SHA} -->"
383383
384384
385-
def request_json(method: str, path: str, data: dict[str, Any] | None = None) -> Any:
386-
url = f"https://api.github.com/repos/{REPOSITORY}{path}"
385+
def request_api_json(method: str, path: str, data: dict[str, Any] | None = None) -> Any:
386+
url = f"https://api.github.com{path}"
387387
body = None if data is None else json.dumps(data).encode()
388388
request = urllib.request.Request(url, data=body, method=method)
389389
request.add_header("Accept", "application/vnd.github+json")
@@ -402,6 +402,18 @@ jobs:
402402
return None if not payload else json.loads(payload)
403403
404404
405+
def request_json(method: str, path: str, data: dict[str, Any] | None = None) -> Any:
406+
return request_api_json(method, f"/repos/{REPOSITORY}{path}", data)
407+
408+
409+
def try_request_api_json(method: str, path: str, data: dict[str, Any] | None = None) -> Any:
410+
try:
411+
return request_api_json(method, path, data)
412+
except RuntimeError as error:
413+
print(f"warning: could not resolve publisher identity from {path}: {error}", file=sys.stderr)
414+
return None
415+
416+
405417
def request_pages(path: str) -> list[dict[str, Any]]:
406418
page = 1
407419
items: list[dict[str, Any]] = []
@@ -435,19 +447,44 @@ jobs:
435447
return str(user.get("login") or "")
436448
437449
438-
def marker_bodies(path: str) -> list[str]:
450+
def publisher_authors() -> set[str]:
451+
# Installation tokens may not expose `/user` or `/app`; keep the
452+
# default Actions authors when identity discovery is unavailable.
453+
authors = set(BOT_AUTHORS)
454+
455+
viewer_payload = try_request_api_json("POST", "/graphql", {"query": "query { viewer { login } }"})
456+
if isinstance(viewer_payload, dict):
457+
viewer_data = viewer_payload.get("data")
458+
if isinstance(viewer_data, dict):
459+
graphql_viewer = viewer_data.get("viewer")
460+
if isinstance(graphql_viewer, dict):
461+
graphql_login = str(graphql_viewer.get("login") or "")
462+
if graphql_login:
463+
authors.add(graphql_login)
464+
465+
viewer = try_request_api_json("GET", "/user")
466+
if isinstance(viewer, dict):
467+
login = str(viewer.get("login") or "")
468+
if login:
469+
authors.add(login)
470+
471+
return authors
472+
473+
474+
def marker_bodies(path: str, authors: set[str]) -> list[str]:
439475
bodies: list[str] = []
440476
for item in request_pages(path):
441-
if author_login(item) in BOT_AUTHORS:
477+
if author_login(item) in authors:
442478
bodies.append(str(item.get("body") or ""))
443479
return bodies
444480
445481
446482
def existing_markers() -> set[str]:
483+
authors = publisher_authors()
447484
bodies: list[str] = []
448-
bodies.extend(marker_bodies(f"/pulls/{PR_NUMBER}/comments"))
449-
bodies.extend(marker_bodies(f"/pulls/{PR_NUMBER}/reviews"))
450-
bodies.extend(marker_bodies(f"/issues/{PR_NUMBER}/comments"))
485+
bodies.extend(marker_bodies(f"/pulls/{PR_NUMBER}/comments", authors))
486+
bodies.extend(marker_bodies(f"/pulls/{PR_NUMBER}/reviews", authors))
487+
bodies.extend(marker_bodies(f"/issues/{PR_NUMBER}/comments", authors))
451488
markers: set[str] = set()
452489
for body in bodies:
453490
for line in body.splitlines():

0 commit comments

Comments
 (0)