diff --git a/.lint/codespell_ignore_words.txt b/.lint/codespell_ignore_words.txt index d2fdbb76..92350d4d 100644 --- a/.lint/codespell_ignore_words.txt +++ b/.lint/codespell_ignore_words.txt @@ -4,6 +4,7 @@ assertIn EHR ehr +fpr INFOR Infor infor diff --git a/src/holoscan_cli/utils/host_setup.py b/src/holoscan_cli/utils/host_setup.py index 0ea1a837..b6bf9634 100644 --- a/src/holoscan_cli/utils/host_setup.py +++ b/src/holoscan_cli/utils/host_setup.py @@ -47,6 +47,8 @@ "arm64": "fbb763bb818ca8ff3302a7764a95c63a42d80b7f864e87639833c55e59b6aadf", "linux": "a31a87a87593f5ca575d924f5e12cd0fcda1c81528f4cc3aebe0669e1643678f", } +# Published at https://apt.kitware.com/. Update deliberately when Kitware rotates its key. +_KITWARE_ARCHIVE_KEY_FINGERPRINT = "4DBEBE3EEC96E7B8C6EC5BE99E92FDC6C5B9BA75" class PackageInstallationError(Exception): @@ -209,6 +211,15 @@ def get_ubuntu_codename() -> str: # ---- high-level setup_* orchestrators --------------------------------------- +def _is_expected_kitware_key(key_listing: bytes) -> bool: + """Return whether GPG reported only Kitware's expected primary key.""" + records = key_listing.decode(errors="replace").splitlines() + fingerprints = [record.split(":")[9].upper() for record in records if record.startswith("fpr:")] + return sum(record.startswith("pub:") for record in records) == 1 and fingerprints[:1] == [ + _KITWARE_ARCHIVE_KEY_FINGERPRINT + ] + + def setup_cmake(min_version: str = "3.26.4", dry_run: bool = False) -> None: """Setup CMake from Kitware if needed""" global _apt_updated @@ -240,6 +251,24 @@ def setup_cmake(min_version: str = "3.26.4", dry_run: bool = False) -> None: check=True, capture_output=True, ).stdout + key_listing = subprocess.run( + [ + gpg, + "--batch", + "--no-options", + "--with-colons", + "--fingerprint", + "--show-keys", + ], + input=key, + check=True, + capture_output=True, + ).stdout + if not _is_expected_kitware_key(key_listing): + fatal( + "Kitware apt archive key fingerprint verification failed: " + f"expected {_KITWARE_ARCHIVE_KEY_FINGERPRINT}." + ) dearmored = subprocess.run( [gpg, "--dearmor"], input=key, diff --git a/tests/unit/test_host_setup.py b/tests/unit/test_host_setup.py index e1635f5b..b107550f 100644 --- a/tests/unit/test_host_setup.py +++ b/tests/unit/test_host_setup.py @@ -8,6 +8,15 @@ from holoscan_cli.utils import host_setup +def test_kitware_key_requires_one_matching_primary_key(): + expected = host_setup._KITWARE_ARCHIVE_KEY_FINGERPRINT.encode() + listing = b"pub::::::::::\nfpr:::::::::" + expected + b":\nsub::::::::::\nfpr:::::::::1234:" + + assert host_setup._is_expected_kitware_key(listing) + assert not host_setup._is_expected_kitware_key(listing.replace(expected, b"0" * 40)) + assert not host_setup._is_expected_kitware_key(listing + b"\npub::::::::::") + + def test_install_packages_if_missing_installs_only_missing_and_pinned(monkeypatch): installed = {"already": "1.0.0"} updates = []