diff --git a/.github/actions/contributor-check/action.yml b/.github/actions/contributor-check/action.yml index faef0d9..0e6241a 100644 --- a/.github/actions/contributor-check/action.yml +++ b/.github/actions/contributor-check/action.yml @@ -1,7 +1,8 @@ name: "Contributor Reputation Check" description: > Screens GitHub contributors for account-shape anomalies, cross-repo - credential laundering, and coordination patterns. Delegates to + credential laundering, and coordination patterns. Public comments are + AgentTrust-branded; risk checks delegate to pinned microsoft/agent-governance-toolkit scripts (MIT License). inputs: @@ -112,6 +113,21 @@ runs: --number "$STEP_NUMBER" \ --item-type "$STEP_TYPE" + - name: Apply AgentTrust comment branding + if: ${{ steps.inputs.outputs.type != 'manual' && steps.inputs.outputs.number != '0' }} + shell: bash + env: + GITHUB_TOKEN: ${{ inputs.github-token }} + STEP_NUMBER: ${{ steps.inputs.outputs.number }} + STEP_TYPE: ${{ steps.inputs.outputs.type }} + STEP_TARGET_REPO: ${{ steps.inputs.outputs.target_repo }} + run: | + python "${{ github.action_path }}/brand_comment.py" \ + --github-token "$GITHUB_TOKEN" \ + --target-repo "$STEP_TARGET_REPO" \ + --number "$STEP_NUMBER" \ + --item-type "$STEP_TYPE" + - name: Cleanup if: always() shell: bash diff --git a/.github/actions/contributor-check/brand_comment.py b/.github/actions/contributor-check/brand_comment.py new file mode 100644 index 0000000..75b07d4 --- /dev/null +++ b/.github/actions/contributor-check/brand_comment.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python3 +"""Apply AgentTrust branding to the public contributor-check comment. + +The check implementation delegates to microsoft/agent-governance-toolkit at a +pinned commit. That upstream script owns the risk calculation and writes an +idempotent PR/issue comment. Keep its hidden marker so future runs update the +same comment, but make the visible footer point at the AgentTrust action. +""" + +from __future__ import annotations + +import argparse +import json +from urllib.error import HTTPError +from urllib.request import Request, urlopen + + +MARKER = "" +AGENTTRUST_FOOTER = ( + "*Automated check by " + "[AgentTrust Contributor Check]" + "(https://github.com/agentrust-io/.github/tree/main/.github/actions/contributor-check).*" +) + + +def _api(token: str, method: str, path: str, data: dict | None = None) -> dict | list | None: + url = f"https://api.github.com{path}" + headers = { + "Authorization": f"Bearer {token}", + "Accept": "application/vnd.github+json", + "X-GitHub-Api-Version": "2022-11-28", + } + req = Request(url, method=method, headers=headers) + if data is not None: + req.add_header("Content-Type", "application/json") + req.data = json.dumps(data).encode() + + try: + with urlopen(req, timeout=15) as resp: + return json.loads(resp.read()) + except HTTPError as exc: + if exc.code == 404: + return None + raise + + +def _branded_body(body: str) -> str: + if AGENTTRUST_FOOTER in body: + return body + + lines = body.splitlines() + for index, line in enumerate(lines): + if line.startswith("*Automated check by ") and "Contributor Check" in line: + lines[index] = AGENTTRUST_FOOTER + return "\n".join(lines) + + return f"{body.rstrip()}\n\n{AGENTTRUST_FOOTER}" + + +def main() -> None: + parser = argparse.ArgumentParser(description="Brand contributor-check comment") + parser.add_argument("--github-token", required=True) + parser.add_argument("--target-repo", required=True) + parser.add_argument("--number", type=int, required=True) + parser.add_argument("--item-type", choices=["pr", "issue", "manual"], required=True) + args = parser.parse_args() + + if args.item_type == "manual" or args.number <= 0: + print("No PR/issue comment to brand.") + return + + owner, repo = args.target_repo.split("/", 1) + page = 1 + while True: + comments = _api( + args.github_token, + "GET", + f"/repos/{owner}/{repo}/issues/{args.number}/comments?per_page=100&page={page}", + ) + if not comments: + print("No contributor-check comment found.") + return + + for comment in comments: + body = comment.get("body") or "" + if MARKER not in body: + continue + + branded = _branded_body(body) + if branded == body: + print("Contributor-check comment already has AgentTrust branding.") + return + + _api( + args.github_token, + "PATCH", + f"/repos/{owner}/{repo}/issues/comments/{comment['id']}", + {"body": branded}, + ) + print("Applied AgentTrust branding to contributor-check comment.") + return + + if len(comments) < 100: + print("No contributor-check comment found.") + return + page += 1 + + +if __name__ == "__main__": + main()