commit:     09559c09f2389246ea98261832e281a9baaedbdf
Author:     Arthur Zamarin <arthurzam <AT> gentoo <DOT> org>
AuthorDate: Sat Nov 26 17:06:06 2022 +0000
Commit:     Arthur Zamarin <arthurzam <AT> gentoo <DOT> org>
CommitDate: Fri Jan 20 20:36:42 2023 +0000
URL:        
https://gitweb.gentoo.org/proj/pkgcore/pkgcheck.git/commit/?id=09559c09

GitPkgCommitsCheck: catch SRC_URI mistakes

Resolves: https://github.com/pkgcore/pkgcheck/issues/493
Signed-off-by: Arthur Zamarin <arthurzam <AT> gentoo.org>

 src/pkgcheck/checks/git.py | 67 +++++++++++++++++++++++++++++++++++++++++++++-
 tests/checks/test_git.py   | 55 ++++++++++++++++++++++++++++++++++++-
 2 files changed, 120 insertions(+), 2 deletions(-)

diff --git a/src/pkgcheck/checks/git.py b/src/pkgcheck/checks/git.py
index 6e48d47f..764dfc5d 100644
--- a/src/pkgcheck/checks/git.py
+++ b/src/pkgcheck/checks/git.py
@@ -13,9 +13,11 @@ from urllib.parse import urlparse
 
 from pkgcore.ebuild.misc import sort_keywords
 from pkgcore.ebuild.repository import UnconfiguredTree
+from pkgcore.fetch import fetchable
 from snakeoil import klass
 from snakeoil.mappings import ImmutableDict
 from snakeoil.osutils import pjoin
+from snakeoil.sequences import iflatten_instance
 from snakeoil.strings import pluralism
 
 from .. import base, results, sources
@@ -169,6 +171,38 @@ class MissingMove(results.PackageResult, results.Error):
         return f"renamed package: {self.old} -> {self.new}"
 
 
+class SrcUriChecksumChange(results.PackageResult, results.Error):
+    """SRC_URI changing checksum without distfile rename."""
+
+    def __init__(self, filename, **kwargs):
+        super().__init__(**kwargs)
+        self.filename = filename
+
+    @property
+    def desc(self):
+        return f"{self.filename!r} has different checksums across commits"
+
+
+class SuspiciousSrcUriChange(results.PackageResult, results.Warning):
+    """Suspicious SRC_URI changing URI without distfile rename."""
+
+    def __init__(self, old_uri, new_uri, filename, **kwargs):
+        super().__init__(**kwargs)
+        if isinstance(old_uri, tuple):
+            self.old_uri = f"mirror://{old_uri[0].mirror_name}/{old_uri[1]}"
+        else:
+            self.old_uri = str(old_uri)
+        if isinstance(new_uri, tuple):
+            self.new_uri = f"mirror://{new_uri[0].mirror_name}/{new_uri[1]}"
+        else:
+            self.new_uri = str(new_uri)
+        self.filename = filename
+
+    @property
+    def desc(self):
+        return f"{self.filename!r} has changed SRC_URI from {self.old_uri!r} 
to {self.new_uri!r}"
+
+
 class _RemovalRepo(UnconfiguredTree):
     """Repository of removed packages stored in a temporary directory."""
 
@@ -235,6 +269,8 @@ class GitPkgCommitsCheck(GentooRepoCheck, GitCommitsCheck):
             DroppedUnstableKeywords,
             MissingSlotmove,
             MissingMove,
+            SrcUriChecksumChange,
+            SuspiciousSrcUriChange,
         ]
     )
 
@@ -345,7 +381,34 @@ class GitPkgCommitsCheck(GentooRepoCheck, GitCommitsCheck):
             else:
                 yield MissingSlotmove(old_slot, new_slot, pkg=new_pkg)
 
-    def feed(self, pkgset):
+    def src_uri_changes(self, pkgset):
+        pkg = pkgset[0].unversioned_atom
+
+        try:
+            new_checksums = {
+                fetch.filename: (fetch.chksums, tuple(fetch.uri._uri_source))
+                for pkg in self.repo.match(pkg)
+                for fetch in iflatten_instance(pkg.fetchables, fetchable)
+            }
+
+            old_checksums = {
+                fetch.filename: (fetch.chksums, tuple(fetch.uri._uri_source))
+                for pkg in self.modified_repo(pkgset).match(pkg)
+                for fetch in iflatten_instance(pkg.fetchables, fetchable)
+            }
+        except (IndexError, FileNotFoundError, tarfile.ReadError):
+            # ignore broken ebuild
+            return
+
+        for filename in old_checksums.keys() & new_checksums.keys():
+            old_checksum, old_uri = old_checksums[filename]
+            new_checksum, new_uri = new_checksums[filename]
+            if old_checksum != new_checksum:
+                yield SrcUriChecksumChange(filename, pkg=pkg)
+            elif old_uri != new_uri:
+                yield SuspiciousSrcUriChange(old_uri[0], new_uri[0], filename, 
pkg=pkg)
+
+    def feed(self, pkgset: list[git.GitPkgChange]):
         # Mapping of commit types to pkgs, available commit types can be seen
         # under the --diff-filter option in git log parsing support and are
         # disambiguated as follows:
@@ -407,6 +470,8 @@ class GitPkgCommitsCheck(GentooRepoCheck, GitCommitsCheck):
                 if not pkg.maintainers and newly_added:
                     yield DirectNoMaintainer(pkg=pkg)
 
+        yield from self.src_uri_changes(pkgset)
+
 
 class MissingSignOff(results.CommitResult, results.Error):
     """Local commit with missing sign offs.

diff --git a/tests/checks/test_git.py b/tests/checks/test_git.py
index 0294f0b3..b69893d8 100644
--- a/tests/checks/test_git.py
+++ b/tests/checks/test_git.py
@@ -7,7 +7,7 @@ import pytest
 from pkgcheck.base import PkgcheckUserException
 from pkgcheck.checks import git as git_mod
 from pkgcheck.addons.git import GitCommit
-from pkgcore.ebuild.cpv import VersionedCPV as CPV
+from pkgcore.ebuild.cpv import VersionedCPV as CPV, UnversionedCPV as CP
 from pkgcore.test.misc import FakeRepo
 from snakeoil.cli import arghparse
 from snakeoil.fileutils import touch
@@ -650,6 +650,59 @@ class TestGitPkgCommitsCheck(ReportTestCase):
         self.init_check()
         self.assertNoReport(self.check, self.source)
 
+    def test_checksum_change(self):
+        distfile = [
+            "DIST",
+            "pkgcheck-1.tar.gz",
+            "549746",
+            "BLAKE2B",
+            
"72ed97d93674ffd311978d03ad3738494a752bf1b02bea5eaaaf1b066c48e8c9ec5f82b79baeeabf3e56e618c76614ee6179b7115d1d875364ac6e3fbc3c6028",
+            "SHA512",
+            
"6a8c135ca44ccbfe15548bd396aba9448c29f60147920b18b8be5aa5fcd1200e0b75bc5de50fc7892ad5460ddad1e7d28a7e44025bdc581a518d136eda8b0df2",
+        ]
+        with open(pjoin(self.parent_repo.path, "profiles/thirdpartymirrors"), 
"a") as f:
+            f.write("gentoo  https://gentoo.org/distfiles\n";)
+        self.parent_repo.create_ebuild("cat/pkg-1", 
src_uri=f"mirror://gentoo/{distfile[1]}")
+        with open(pjoin(self.parent_repo.path, "cat/pkg/Manifest"), "w") as f:
+            f.write(" ".join(distfile) + "\n")
+        self.parent_git_repo.add_all("cat/pkg: add 1", signoff=True)
+        # pull changes and change checksum in child repo
+        self.child_git_repo.run(["git", "pull", "origin", "main"])
+        self.child_repo.create_ebuild("cat/pkg-1-r1", 
src_uri=f"mirror://gentoo/{distfile[1]}")
+        distfile[-1] = distfile[-1][:-1] + "0"
+        with open(pjoin(self.child_repo.path, "cat/pkg/Manifest"), "w") as f:
+            f.write(" ".join(distfile) + "\n")
+        self.child_git_repo.add_all("cat/pkg: revbump", signoff=True)
+        self.init_check()
+        r = self.assertReport(self.check, self.source)
+        assert r == git_mod.SrcUriChecksumChange(distfile[1], 
pkg=CP("cat/pkg"))
+
+    def test_src_uri_change(self):
+        distfile = [
+            "DIST",
+            "pkgcheck-1.tar.gz",
+            "549746",
+            "BLAKE2B",
+            
"72ed97d93674ffd311978d03ad3738494a752bf1b02bea5eaaaf1b066c48e8c9ec5f82b79baeeabf3e56e618c76614ee6179b7115d1d875364ac6e3fbc3c6028",
+            "SHA512",
+            
"6a8c135ca44ccbfe15548bd396aba9448c29f60147920b18b8be5aa5fcd1200e0b75bc5de50fc7892ad5460ddad1e7d28a7e44025bdc581a518d136eda8b0df2",
+        ]
+        old_url = f"mirror://gentoo/{distfile[1]}"
+        new_url = f"https://pkgcore.github.io/pkgcheck/{distfile[1]}";
+        with open(pjoin(self.parent_repo.path, "profiles/thirdpartymirrors"), 
"a") as f:
+            f.write("gentoo  https://gentoo.org/distfiles\n";)
+        self.parent_repo.create_ebuild("cat/pkg-1", src_uri=old_url)
+        with open(pjoin(self.parent_repo.path, "cat/pkg/Manifest"), "w") as f:
+            f.write(" ".join(distfile) + "\n")
+        self.parent_git_repo.add_all("cat/pkg: add 1", signoff=True)
+        # pull changes and change checksum in child repo
+        self.child_git_repo.run(["git", "pull", "origin", "main"])
+        self.child_repo.create_ebuild("cat/pkg-1", src_uri=new_url)
+        self.child_git_repo.add_all("cat/pkg: change SRC_URI", signoff=True)
+        self.init_check()
+        r = self.assertReport(self.check, self.source)
+        assert r == git_mod.SuspiciousSrcUriChange(old_url, new_url, 
distfile[1], pkg=CP("cat/pkg"))
+
 
 class TestGitEclassCommitsCheck(ReportTestCase):
 

Reply via email to