From f9a2dc8d37cf664d4a58904bcd696f92c3d0be93 Mon Sep 17 00:00:00 2001 From: Sunny Date: Fri, 3 Apr 2026 22:26:44 +0000 Subject: [PATCH] Replace inxi with repolib Replaces inxi for gathering the repository signed-by key path with repolib. Executing inxi as a subprocess results in output in unexpected format under certain circumstances. The same can be gathered used repolib, in python, which is already used for loading the sources. `inxi -r` doesn't list the signed-by value for Deb822 sources. repolib supports extracting signed-by value for both legacy and Deb822 formatted sources. Adds basic unit tests that verifies the repository key path retrieval for various scenarios. --- README.md | 7 +++ debian/control | 1 - tests/__init__.py | 0 tests/test_mintSources.py | 45 ++++++++++++++++++++ tests/testdata/sources.list.d/hypnotix.list | 1 + tests/testdata/sources.list.d/nemo.sources | 7 +++ tests/testdata/sources.list.d/pix.sources | 7 +++ tests/testdata/sources.list.d/sticky.list | 1 + tests/testdata/sources.list.d/xviewer.list | 2 + usr/lib/linuxmint/mintSources/mintSources.py | 25 ++++++++--- 10 files changed, 89 insertions(+), 7 deletions(-) create mode 100644 tests/__init__.py create mode 100644 tests/test_mintSources.py create mode 100644 tests/testdata/sources.list.d/hypnotix.list create mode 100644 tests/testdata/sources.list.d/nemo.sources create mode 100644 tests/testdata/sources.list.d/pix.sources create mode 100644 tests/testdata/sources.list.d/sticky.list create mode 100644 tests/testdata/sources.list.d/xviewer.list diff --git a/README.md b/README.md index 8d1cd11d..e18dd9ee 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,13 @@ cd .. sudo dpkg -i mintsources*.deb ``` +## Test + +Run the tests from the root of the project +``` +python3 -m unittest +``` + ## Translations Please use Launchpad to translate Mintsources: https://translations.launchpad.net/linuxmint/latest/. diff --git a/debian/control b/debian/control index b3e5237d..cea94f3c 100644 --- a/debian/control +++ b/debian/control @@ -21,7 +21,6 @@ Depends: python3-apt, gir1.2-pango-1.0, gir1.2-xapp-1.0, iso-flag-png, - inxi, lsb-release, mint-mirrors, ${misc:Depends}, diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/test_mintSources.py b/tests/test_mintSources.py new file mode 100644 index 00000000..c3ce4566 --- /dev/null +++ b/tests/test_mintSources.py @@ -0,0 +1,45 @@ +import sys, os + +tests_path = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, tests_path + "/../usr/lib/linuxmint/mintSources/") + +from pathlib import Path +import unittest + +import repolib + +from mintSources import repo_key_path + + +class MintSources(unittest.TestCase): + def test_repo_key_path(self): + repolib.util.SOURCES_DIR = Path(tests_path, "testdata", "sources.list.d") + repolib.load_all_sources() + + nemo_uri = "https://nemo.linuxmint.com" + xviewer_uri = "https://xviewer.linuxmint.com" + xviewerdev_uri = "https://xviewer-dev.linuxmint.com" + sticky_uri = "https://sticky.linuxmint.com" + hypnotix_uri = "https://hypnotix.linuxmint.com" + pix_uri = "https://pix.linuxmint.com" + + # Deb822 source format. + self.assertEqual(repo_key_path(nemo_uri), "/usr/share/keyrings/nemo.gpg") + # Legacy source format. + self.assertEqual(repo_key_path(xviewer_uri), "/usr/share/keyrings/xviewer.gpg") + # Input URI with trailing slash. + self.assertEqual(repo_key_path(nemo_uri + "/"), "/usr/share/keyrings/nemo.gpg") + # Source repository URI with trailing slash. + self.assertEqual( + repo_key_path(xviewerdev_uri), "/usr/share/keyrings/xviewer-dev.gpg" + ) + # Not signed-by source. + self.assertEqual(repo_key_path(sticky_uri), None) + # Signed but disabled Deb822 source format. + self.assertEqual(repo_key_path(pix_uri), None) + # Signed but disabled legacy source format. + self.assertEqual(repo_key_path(hypnotix_uri), None) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/testdata/sources.list.d/hypnotix.list b/tests/testdata/sources.list.d/hypnotix.list new file mode 100644 index 00000000..49c5b679 --- /dev/null +++ b/tests/testdata/sources.list.d/hypnotix.list @@ -0,0 +1 @@ +#deb [signed-by=/usr/share/keyrings/hypnotix.gpg] https://hypnotix.linuxmint.com zena main diff --git a/tests/testdata/sources.list.d/nemo.sources b/tests/testdata/sources.list.d/nemo.sources new file mode 100644 index 00000000..d172c5f6 --- /dev/null +++ b/tests/testdata/sources.list.d/nemo.sources @@ -0,0 +1,7 @@ +Types: deb +URIs: https://nemo.linuxmint.com +Enabled: yes +Suites: stable +Components: main +Architectures: amd64 +Signed-By: /usr/share/keyrings/nemo.gpg diff --git a/tests/testdata/sources.list.d/pix.sources b/tests/testdata/sources.list.d/pix.sources new file mode 100644 index 00000000..c7984ad6 --- /dev/null +++ b/tests/testdata/sources.list.d/pix.sources @@ -0,0 +1,7 @@ +Types: deb +URIs: https://pix.linuxmint.com +Enabled: no +Suites: stable +Components: main +Architectures: amd64 +Signed-By: /usr/share/keyrings/nemo.gpg diff --git a/tests/testdata/sources.list.d/sticky.list b/tests/testdata/sources.list.d/sticky.list new file mode 100644 index 00000000..5fae70c7 --- /dev/null +++ b/tests/testdata/sources.list.d/sticky.list @@ -0,0 +1 @@ +deb https://sticky.linuxmint.com zena main diff --git a/tests/testdata/sources.list.d/xviewer.list b/tests/testdata/sources.list.d/xviewer.list new file mode 100644 index 00000000..17766fb5 --- /dev/null +++ b/tests/testdata/sources.list.d/xviewer.list @@ -0,0 +1,2 @@ +deb [signed-by=/usr/share/keyrings/xviewer.gpg] https://xviewer.linuxmint.com zena main +deb [signed-by=/usr/share/keyrings/xviewer-dev.gpg] https://xviewer-dev.linuxmint.com/ zena main diff --git a/usr/lib/linuxmint/mintSources/mintSources.py b/usr/lib/linuxmint/mintSources/mintSources.py index ff9060fb..27fb9bd9 100755 --- a/usr/lib/linuxmint/mintSources/mintSources.py +++ b/usr/lib/linuxmint/mintSources/mintSources.py @@ -300,6 +300,22 @@ def expand_http_line(line, distro_codename): line = "deb %s %s %s" % ( repo, distro_codename, areas ) return line +def repo_key_path(uri): + """ + Returns the key path for a given repository URI for enabled sources. + + NOTE: Must load all the sources with repolib.load_all_sources() once before + calling this. + """ + uri = uri.removesuffix("/") + for source in repolib.sources.values(): + if source.enabled == repolib.AptSourceEnabled.FALSE or not source.signed_by: + continue + for u in source.uris: + if uri == u.removesuffix("/"): + return source.signed_by + return None + class CurlCallback: def __init__(self): self.contents = '' @@ -1209,15 +1225,12 @@ def __init__(self, path, uri): r = re.compile(r"^gpg\:\s+using \S+ key (.+)$", re.MULTILINE | re.IGNORECASE) # try to verify all repository lists using gpg + repolib.load_all_sources() for repository in repositories: # if the repository is "signed-by", just check that the key file is present uri = repository.uri - if uri.endswith("/"): - uri = uri[:-1] - output = subprocess.getoutput(f"inxi -r | grep {uri}") - key_path = None - if "signed-by" in output: - key_path = output.split("signed-by=")[1].split("]")[0] + key_path = repo_key_path(uri) + if key_path: print(f"{uri} is signed by {key_path}") if os.path.exists(key_path): print(" Key found.")