diff --git a/moderation/verify_catalog.py b/moderation/verify_catalog.py index 3108d0a..871d975 100644 --- a/moderation/verify_catalog.py +++ b/moderation/verify_catalog.py @@ -81,7 +81,10 @@ def verify(number: int, source_number: int) -> tuple[str, str]: if (moderation is None or moderation["state"] != "success" or (moderation.get("creator") or {}).get("login") != APP_LOGIN): raise VerificationError("Source bot has no successful moderator App status") - git("merge-base", "--is-ancestor", source["merge_commit_sha"], base) + try: + git("diff", "--quiet", source["head"]["sha"], base, "--", source_directory) + except subprocess.CalledProcessError as error: + raise VerificationError("Merged source bot content differs from current main") from error subprocess.run(["git", "fetch", "--no-tags", "origin", f"+refs/pull/{number}/head:refs/remotes/origin/catalog-verify"], check=True) if git("rev-parse", "refs/remotes/origin/catalog-verify") != head: raise VerificationError("Catalog PR head changed during verification") diff --git a/tests/test_moderation.py b/tests/test_moderation.py index 4cb6111..0bf4193 100644 --- a/tests/test_moderation.py +++ b/tests/test_moderation.py @@ -5,7 +5,7 @@ import json from datetime import UTC, datetime from pathlib import Path -from subprocess import CompletedProcess +from subprocess import CalledProcessError, CompletedProcess from unittest.mock import patch from moderation import assess, moderate, verify_catalog @@ -219,10 +219,11 @@ def test_catalog_must_match_trusted_regeneration(self): "bots/owners.json": "{}\n"} regenerated = proposed.copy() source = {"merged_at": generated_at, "base": {"ref": "main"}, - "head": {"sha": "d" * 40}, "merge_commit_sha": "e" * 40, + "head": {"sha": "d" * 40}, "user": {"login": "contributor"}} statuses = [{"context": moderate.CONTEXT, "state": "success", "creator": {"login": verify_catalog.APP_LOGIN}}] + source_matches_main = [True] def fake_api(method, path, payload=None): if path == "pulls/12": @@ -246,7 +247,9 @@ def fake_git(*args): return "bots/index.json" if args[0] == "show": return proposed[args[1].split(":", 1)[1]].strip() - if args[:2] == ("merge-base", "--is-ancestor"): + if args[:2] == ("diff", "--quiet"): + if not source_matches_main[0]: + raise CalledProcessError(1, ["git", *args]) return "" raise AssertionError(args) @@ -261,6 +264,10 @@ def fake_git(*args): with self.assertRaisesRegex(verify_catalog.VerificationError, "Generated content differs"): verify_catalog.verify(12, 7) regenerated["bots/owners.json"] = proposed["bots/owners.json"] + source_matches_main[0] = False + with self.assertRaisesRegex(verify_catalog.VerificationError, "source bot content differs"): + verify_catalog.verify(12, 7) + source_matches_main[0] = True statuses[0]["creator"] = {"login": "untrusted"} with self.assertRaisesRegex(verify_catalog.VerificationError, "no successful moderator App status"): verify_catalog.verify(12, 7)