summaryrefslogtreecommitdiffstats
path: root/tests/test_signed_usable.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_signed_usable.py')
-rw-r--r--tests/test_signed_usable.py403
1 files changed, 403 insertions, 0 deletions
diff --git a/tests/test_signed_usable.py b/tests/test_signed_usable.py
new file mode 100644
index 0000000..1bd5087
--- /dev/null
+++ b/tests/test_signed_usable.py
@@ -0,0 +1,403 @@
+#!/usr/bin/python3
+#
+# Copyright (C) 2019 Canonical Ltd
+#
+# SPDX-License-Identifier: GPL-2.0+
+
+
+import base64
+import os
+import shutil
+import tempfile
+import unittest
+
+import apt_pkg
+import testcommon
+
+import apt
+import apt.progress.base
+import apt.progress.text
+
+# A change in APT to early fail acquire items with weak hashes caused it
+# to call progress methods before calling Start(), which confused python-apt's
+# locking handling. Hence we need to skip such tests for now, until we can test
+# against an apt version with the fix:
+#
+# https://salsa.debian.org/apt-team/apt/commit/84176f6c
+#
+RUN_CRASHING_TESTS = False
+
+# Message APT gives us when hashes are too weak
+CACHE_MSG_WEAK_HASH = (
+ "Insufficient information available to perform this download securely"
+)
+
+
+class TestSignedUsable(testcommon.TestCase):
+ """Test fetch_binary() and fetch_source() signature checking."""
+
+ def setUp(self):
+ testcommon.TestCase.setUp(self)
+ apt_pkg.config.clear("APT::Update::Post-Invoke")
+ apt_pkg.config.clear("APT::Update::Post-Invoke-Success")
+ self.chroot_path = chroot_path = tempfile.mkdtemp()
+ repo_path = os.path.abspath("./data/test-signed-usable-repo/")
+ # Inits the dirs for us
+ apt.cache.Cache(rootdir=chroot_path)
+ # Change directory
+ self.cwd = os.getcwd()
+ os.chdir(chroot_path)
+ with open(
+ os.path.join(self.chroot_path, "etc/apt/sources.list"), "w"
+ ) as sources_list:
+ sources_list.write("deb copy:%s/signed/ /\n" % repo_path)
+ sources_list.write("deb copy:%s/unsigned/ /\n" % repo_path)
+ sources_list.write("deb-src copy:%s/signed/ /\n" % repo_path)
+ sources_list.write("deb-src copy:%s/unsigned/ /\n" % repo_path)
+
+ with open(os.path.join(repo_path, "key.gpg.base64"), "rb") as pubkey64:
+ with open(
+ os.path.join(self.chroot_path, "etc/apt/trusted.gpg"), "wb"
+ ) as tgt:
+ tgt.write(base64.b64decode(pubkey64.read()))
+
+ self.cache = apt.cache.Cache(rootdir=chroot_path)
+ apt_pkg.config["Acquire::AllowInsecureRepositories"] = "true"
+ self.cache.update()
+ apt_pkg.config["Acquire::AllowInsecureRepositories"] = "false"
+ self.cache.open()
+
+ self.progress = apt.progress.text.AcquireProgress
+ apt.progress.text.AcquireProgress = apt.progress.base.AcquireProgress
+
+ # Disable actual installation of downloaded items
+ self.cache.install_archives = (
+ lambda *a, **b: apt_pkg.PackageManager.RESULT_COMPLETED
+ )
+
+ def tearDown(self):
+ # this resets the rootdir apt_pkg.config to ensure it does not
+ # "pollute" the later tests
+ apt.cache.Cache(rootdir="/")
+ os.chdir(self.cwd)
+ shutil.rmtree(self.chroot_path)
+
+ apt.progress.text.AcquireProgress = self.progress
+
+ def doInstall(self, name, bargs):
+ self.cache[name].mark_install()
+ try:
+ with apt.progress.base.InstallProgress() as ip:
+ self.cache.commit(install_progress=ip, **bargs)
+ finally:
+ for fname in os.listdir(
+ os.path.join(self.chroot_path, "var/cache/apt/archives")
+ ):
+ if os.path.isfile(
+ os.path.join(self.chroot_path, "var/cache/apt/archives", fname)
+ ):
+ os.unlink(
+ os.path.join(self.chroot_path, "var/cache/apt/archives", fname)
+ )
+ self.cache[name].mark_keep()
+
+ def doFetchArchives(self, name, bargs):
+ fetcher = apt_pkg.Acquire()
+ self.cache[name].mark_install()
+ try:
+ self.cache.fetch_archives(fetcher=fetcher, **bargs)
+ finally:
+ for fname in os.listdir(
+ os.path.join(self.chroot_path, "var/cache/apt/archives")
+ ):
+ if fname.endswith(".deb"):
+ os.unlink(
+ os.path.join(self.chroot_path, "var/cache/apt/archives", fname)
+ )
+ self.cache[name].mark_keep()
+
+ def testDefaultDenyButExplicitAllowUnauthenticated(self):
+ """Deny by config (default), but pass allow_unauthenticated=True"""
+
+ bargs = dict(allow_unauthenticated=True)
+ sargs = dict(allow_unauthenticated=True, unpack=False)
+
+ self.doInstall("signed-usable", bargs)
+ if RUN_CRASHING_TESTS:
+ self.assertRaisesRegex(
+ apt.cache.FetchFailedException,
+ CACHE_MSG_WEAK_HASH,
+ self.doInstall,
+ "signed-not-usable",
+ bargs,
+ )
+
+ self.doInstall("unsigned-usable", bargs)
+ if RUN_CRASHING_TESTS:
+ self.assertRaisesRegex(
+ apt.cache.FetchFailedException,
+ CACHE_MSG_WEAK_HASH,
+ self.doInstall,
+ "unsigned-unusable",
+ bargs,
+ )
+
+ self.doFetchArchives("signed-usable", bargs)
+ self.doFetchArchives("unsigned-usable", bargs)
+ self.assertRaisesRegex(
+ apt.cache.FetchFailedException,
+ CACHE_MSG_WEAK_HASH,
+ self.doFetchArchives,
+ "signed-not-usable",
+ bargs,
+ )
+ self.assertRaisesRegex(
+ apt.cache.FetchFailedException,
+ CACHE_MSG_WEAK_HASH,
+ self.doFetchArchives,
+ "unsigned-unusable",
+ bargs,
+ )
+
+ self.cache["signed-usable"].candidate.fetch_binary(**bargs)
+ self.cache["signed-usable"].candidate.fetch_source(**sargs)
+ self.cache["signed-not-usable"].candidate.fetch_binary(**bargs)
+ self.cache["signed-not-usable"].candidate.fetch_source(**sargs)
+ self.cache["unsigned-usable"].candidate.fetch_binary(**bargs)
+ self.cache["unsigned-usable"].candidate.fetch_source(**sargs)
+ self.cache["unsigned-unusable"].candidate.fetch_binary(**bargs)
+ self.cache["unsigned-unusable"].candidate.fetch_source(**sargs)
+
+ def testDefaultAllow(self):
+ """Allow by config APT::Get::AllowUnauthenticated = True"""
+ apt_pkg.config["APT::Get::AllowUnauthenticated"] = "true"
+
+ bargs = dict()
+ sargs = dict(unpack=False)
+
+ self.doInstall("signed-usable", bargs)
+ if RUN_CRASHING_TESTS:
+ self.assertRaisesRegex(
+ apt.cache.FetchFailedException,
+ CACHE_MSG_WEAK_HASH,
+ self.doInstall,
+ "signed-not-usable",
+ bargs,
+ )
+ self.doInstall("unsigned-usable", bargs)
+ if RUN_CRASHING_TESTS:
+ self.assertRaisesRegex(
+ apt.cache.FetchFailedException,
+ CACHE_MSG_WEAK_HASH,
+ self.doInstall,
+ "unsigned-unusable",
+ bargs,
+ )
+
+ self.doFetchArchives("signed-usable", bargs)
+ self.doFetchArchives("unsigned-usable", bargs)
+ self.assertRaisesRegex(
+ apt.cache.FetchFailedException,
+ CACHE_MSG_WEAK_HASH,
+ self.doFetchArchives,
+ "signed-not-usable",
+ bargs,
+ )
+ self.assertRaisesRegex(
+ apt.cache.FetchFailedException,
+ CACHE_MSG_WEAK_HASH,
+ self.doFetchArchives,
+ "unsigned-unusable",
+ bargs,
+ )
+
+ self.cache["signed-usable"].candidate.fetch_binary(**bargs)
+ self.cache["signed-usable"].candidate.fetch_source(**sargs)
+ self.cache["signed-not-usable"].candidate.fetch_binary(**bargs)
+ self.cache["signed-not-usable"].candidate.fetch_source(**sargs)
+ self.cache["unsigned-usable"].candidate.fetch_binary(**bargs)
+ self.cache["unsigned-usable"].candidate.fetch_source(**sargs)
+ self.cache["unsigned-unusable"].candidate.fetch_binary(**bargs)
+ self.cache["unsigned-unusable"].candidate.fetch_source(**sargs)
+
+ def testDefaultDeny(self):
+ """Test APT::Get::AllowUnauthenticated = False (default)"""
+ self.doInstall("signed-usable", {})
+ if RUN_CRASHING_TESTS:
+ self.assertRaisesRegex(
+ apt.cache.FetchFailedException,
+ CACHE_MSG_WEAK_HASH,
+ self.doInstall,
+ "signed-not-usable",
+ {},
+ )
+ self.assertRaisesRegex(
+ apt.cache.UntrustedException,
+ "Untrusted packages:",
+ self.doInstall,
+ "unsigned-usable",
+ {},
+ )
+ self.assertRaisesRegex(
+ apt.cache.UntrustedException,
+ "Untrusted packages:",
+ self.doInstall,
+ "unsigned-unusable",
+ {},
+ )
+
+ self.doFetchArchives("signed-usable", {})
+ self.assertRaisesRegex(
+ apt.cache.FetchFailedException,
+ CACHE_MSG_WEAK_HASH,
+ self.doFetchArchives,
+ "signed-not-usable",
+ {},
+ )
+ self.assertRaisesRegex(
+ apt.cache.UntrustedException,
+ "Untrusted packages:",
+ self.doFetchArchives,
+ "unsigned-usable",
+ {},
+ )
+ self.assertRaisesRegex(
+ apt.cache.UntrustedException,
+ "Untrusted packages:",
+ self.doFetchArchives,
+ "unsigned-unusable",
+ {},
+ )
+
+ self.cache["signed-usable"].candidate.fetch_binary()
+ self.cache["signed-usable"].candidate.fetch_source(unpack=False)
+ self.assertRaisesRegex(
+ apt.package.UntrustedError,
+ ": No trusted hash",
+ self.cache["signed-not-usable"].candidate.fetch_binary,
+ )
+ self.assertRaisesRegex(
+ apt.package.UntrustedError,
+ ": No trusted hash",
+ self.cache["signed-not-usable"].candidate.fetch_source,
+ unpack=False,
+ )
+ self.assertRaisesRegex(
+ apt.package.UntrustedError,
+ ": Source",
+ self.cache["unsigned-usable"].candidate.fetch_binary,
+ )
+ self.assertRaisesRegex(
+ apt.package.UntrustedError,
+ ": Source",
+ self.cache["unsigned-usable"].candidate.fetch_source,
+ unpack=False,
+ )
+ self.assertRaisesRegex(
+ apt.package.UntrustedError,
+ ": Source",
+ self.cache["unsigned-unusable"].candidate.fetch_binary,
+ )
+ self.assertRaisesRegex(
+ apt.package.UntrustedError,
+ ": Source",
+ self.cache["unsigned-unusable"].candidate.fetch_source,
+ unpack=False,
+ )
+
+ def testDefaultAllowButExplicitDeny(self):
+ """Allow by config, but pass allow_unauthenticated=False"""
+ apt_pkg.config["APT::Get::AllowUnauthenticated"] = "true"
+
+ bargs = dict(allow_unauthenticated=False)
+ sargs = dict(allow_unauthenticated=False, unpack=False)
+
+ self.doInstall("signed-usable", bargs)
+ if RUN_CRASHING_TESTS:
+ self.assertRaisesRegex(
+ apt.cache.FetchFailedException,
+ CACHE_MSG_WEAK_HASH,
+ self.doInstall,
+ "signed-not-usable",
+ bargs,
+ )
+ self.assertRaisesRegex(
+ apt.cache.UntrustedException,
+ "Untrusted packages:",
+ self.doInstall,
+ "unsigned-usable",
+ bargs,
+ )
+ self.assertRaisesRegex(
+ apt.cache.UntrustedException,
+ "Untrusted packages:",
+ self.doInstall,
+ "unsigned-unusable",
+ bargs,
+ )
+
+ self.doFetchArchives("signed-usable", bargs)
+ self.assertRaisesRegex(
+ apt.cache.FetchFailedException,
+ CACHE_MSG_WEAK_HASH,
+ self.doFetchArchives,
+ "signed-not-usable",
+ bargs,
+ )
+ self.assertRaisesRegex(
+ apt.cache.UntrustedException,
+ "Untrusted packages:",
+ self.doFetchArchives,
+ "unsigned-usable",
+ bargs,
+ )
+ self.assertRaisesRegex(
+ apt.cache.UntrustedException,
+ "Untrusted packages:",
+ self.doFetchArchives,
+ "unsigned-unusable",
+ bargs,
+ )
+
+ self.cache["signed-usable"].candidate.fetch_binary(**bargs)
+ self.cache["signed-usable"].candidate.fetch_source(**sargs)
+ self.assertRaisesRegex(
+ apt.package.UntrustedError,
+ ": No trusted hash",
+ self.cache["signed-not-usable"].candidate.fetch_binary,
+ **bargs
+ )
+ self.assertRaisesRegex(
+ apt.package.UntrustedError,
+ ": No trusted hash",
+ self.cache["signed-not-usable"].candidate.fetch_source,
+ **sargs
+ )
+ self.assertRaisesRegex(
+ apt.package.UntrustedError,
+ ": Source",
+ self.cache["unsigned-usable"].candidate.fetch_binary,
+ **bargs
+ )
+ self.assertRaisesRegex(
+ apt.package.UntrustedError,
+ ": Source",
+ self.cache["unsigned-usable"].candidate.fetch_source,
+ **sargs
+ )
+ self.assertRaisesRegex(
+ apt.package.UntrustedError,
+ ": Source",
+ self.cache["unsigned-unusable"].candidate.fetch_binary,
+ **bargs
+ )
+ self.assertRaisesRegex(
+ apt.package.UntrustedError,
+ ": Source",
+ self.cache["unsigned-unusable"].candidate.fetch_source,
+ **sargs
+ )
+
+
+if __name__ == "__main__":
+ unittest.main()