From 984e2f5146e87b4b62424eb43f42c8898e2c25c6 Mon Sep 17 00:00:00 2001 From: Mike McLean Date: Mon, 11 Aug 2025 16:38:18 -0400 Subject: [PATCH 1/4] extra validation for sigkey values --- kojihub/kojihub.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/kojihub/kojihub.py b/kojihub/kojihub.py index 69d6eaf5..9b0222f1 100644 --- a/kojihub/kojihub.py +++ b/kojihub/kojihub.py @@ -8273,7 +8273,7 @@ def add_rpm_sig(an_rpm, sighdr, sigkey=None): if not os.path.isdir(builddir): raise koji.GenericError("No such directory: %s" % builddir) if sigkey is not None: - verify_name_internal(sigkey) + validate_sigkey_value(sigkey) # verify sigmd5 matches rpm and pick sigkey if needed rawhdr = koji.RawHeader(sighdr) @@ -8324,10 +8324,18 @@ def add_rpm_sig(an_rpm, sighdr, sigkey=None): sigkey=sigkey, sighash=sighash, build=binfo, rpm=rinfo) +def validate_sigkey_value(sigkey): + convert_value(sigkey, cast=str, check_only=True) + if '/' in sigkey or sigkey.startswith('.'): + # not allowed because the value is used in a path + raise koji.GenericError("Invalid sigkey value") + verify_name_internal(sigkey) + + def rename_rpm_sig(rpminfo, oldkey, newkey): """Change the sigkey for an rpm signature""" - verify_name_internal(newkey) + validate_sigkey_value(newkey) rinfo = get_rpm(rpminfo, strict=True) nvra = "%(name)s-%(version)s-%(release)s.%(arch)s" % rinfo if rinfo['external_repo_id']: From 8ba268eecc473b0e6744e16c9f297db89a7a92ea Mon Sep 17 00:00:00 2001 From: Mike McLean Date: Mon, 11 Aug 2025 17:20:43 -0400 Subject: [PATCH 2/4] tweak unit test --- tests/test_hub/test_add_rpm_sig.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/tests/test_hub/test_add_rpm_sig.py b/tests/test_hub/test_add_rpm_sig.py index 3505d3d4..fcf62b0d 100644 --- a/tests/test_hub/test_add_rpm_sig.py +++ b/tests/test_hub/test_add_rpm_sig.py @@ -146,15 +146,22 @@ class TestAddRPMSig(unittest.TestCase): def test_add_rpm_sig_bad_sigkey(self): """bad sigkey failure case""" sighdr = 'SIG HEADER 99' - self.isdir.side_effect = [True] - self.get_rpm.side_effect = [{'build_id': 100, 'external_repo_id': None}] + self.isdir.return_value = True + self.get_rpm.return_value = {'build_id': 100, 'external_repo_id': None} - with self.assertRaises(koji.GenericError): - kojihub.add_rpm_sig(1, sighdr, sigkey='foo/bar !') + badkeys = [ + 'white space', + 'badchar!', + '.hidden', + 'sub/dir', + ] + for sigkey in badkeys: + with self.assertRaises(koji.GenericError): + kojihub.add_rpm_sig(1, sighdr, sigkey=sigkey) self.assertEqual(len(self.inserts), 0) self.open.assert_not_called() - self.isdir.assert_called_once() + self.isdir.assert_called() class TestScanHeaderOnly(unittest.TestCase): From 6ea68825c7270d47c833b0ca7c24673b40c16c04 Mon Sep 17 00:00:00 2001 From: Mike McLean Date: Tue, 19 Aug 2025 12:24:42 -0400 Subject: [PATCH 3/4] allow sigkey="" --- kojihub/kojihub.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kojihub/kojihub.py b/kojihub/kojihub.py index 9b0222f1..af6e398c 100644 --- a/kojihub/kojihub.py +++ b/kojihub/kojihub.py @@ -8326,6 +8326,9 @@ def add_rpm_sig(an_rpm, sighdr, sigkey=None): def validate_sigkey_value(sigkey): convert_value(sigkey, cast=str, check_only=True) + if sigkey == '': + # special case for the unsigned sig header + return if '/' in sigkey or sigkey.startswith('.'): # not allowed because the value is used in a path raise koji.GenericError("Invalid sigkey value") From 2734d5276fd92aa6388961dc75d545f008b870a7 Mon Sep 17 00:00:00 2001 From: Mike McLean Date: Tue, 19 Aug 2025 13:05:13 -0400 Subject: [PATCH 4/4] require lowercase sigkey --- kojihub/kojihub.py | 4 ++++ tests/test_hub/test_add_rpm_sig.py | 1 + 2 files changed, 5 insertions(+) diff --git a/kojihub/kojihub.py b/kojihub/kojihub.py index af6e398c..c848bc99 100644 --- a/kojihub/kojihub.py +++ b/kojihub/kojihub.py @@ -8332,6 +8332,10 @@ def validate_sigkey_value(sigkey): if '/' in sigkey or sigkey.startswith('.'): # not allowed because the value is used in a path raise koji.GenericError("Invalid sigkey value") + if sigkey != sigkey.lower(): + # we require lowercase because koji has historically forced lowercase for this value + # e.g. in query_rpm_sigs + raise koji.GenericError("Invalid sigkey value. Must be lowercase") verify_name_internal(sigkey) diff --git a/tests/test_hub/test_add_rpm_sig.py b/tests/test_hub/test_add_rpm_sig.py index fcf62b0d..c40067ae 100644 --- a/tests/test_hub/test_add_rpm_sig.py +++ b/tests/test_hub/test_add_rpm_sig.py @@ -154,6 +154,7 @@ class TestAddRPMSig(unittest.TestCase): 'badchar!', '.hidden', 'sub/dir', + 'hasUPPERcase', ] for sigkey in badkeys: with self.assertRaises(koji.GenericError):