From 9b8ef2ccfa1562cebca65633c4394ffaaf5c3c8b Mon Sep 17 00:00:00 2001 From: omavashia Date: Sun, 20 Jul 2025 05:05:21 +0530 Subject: [PATCH] fix Issue #2418: parse_rfc3339 calling .groups() on None --- kubernetes/base/config/dateutil.py | 52 +++++++++++++++++------------- kubernetes/test/test_api_client.py | 29 +++++++++++++++++ 2 files changed, 59 insertions(+), 22 deletions(-) diff --git a/kubernetes/base/config/dateutil.py b/kubernetes/base/config/dateutil.py index 972e003eba..331067759a 100644 --- a/kubernetes/base/config/dateutil.py +++ b/kubernetes/base/config/dateutil.py @@ -53,29 +53,37 @@ def parse_rfc3339(s): if not s.tzinfo: return s.replace(tzinfo=UTC) return s - groups = _re_rfc3339.search(s).groups() - dt = [0] * 7 - for x in range(6): - dt[x] = int(groups[x]) - us = 0 - if groups[6] is not None: - partial_sec = float(groups[6].replace(",", ".")) - us = int(MICROSEC_PER_SEC * partial_sec) - tz = UTC - if groups[7] is not None and groups[7] != 'Z' and groups[7] != 'z': - tz_groups = _re_timezone.search(groups[7]).groups() - hour = int(tz_groups[1]) - minute = 0 - if tz_groups[0] == "-": - hour *= -1 - if tz_groups[2]: - minute = int(tz_groups[2]) - tz = TimezoneInfo(hour, minute) - return datetime.datetime( - year=dt[0], month=dt[1], day=dt[2], - hour=dt[3], minute=dt[4], second=dt[5], - microsecond=us, tzinfo=tz) + match = _re_rfc3339.search(s) + + if match is None: + raise ValueError(f"Error in RFC339 Date Formatting {s}") + try: + groups = match.groups() + + dt = [0] * 7 + for x in range(6): + dt[x] = int(groups[x]) + us = 0 + if groups[6] is not None: + partial_sec = float(groups[6].replace(",", ".")) + us = int(MICROSEC_PER_SEC * partial_sec) + tz = UTC + if groups[7] is not None and groups[7] != 'Z' and groups[7] != 'z': + tz_groups = _re_timezone.search(groups[7]).groups() + hour = int(tz_groups[1]) + minute = 0 + if tz_groups[0] == "-": + hour *= -1 + if tz_groups[2]: + minute = int(tz_groups[2]) + tz = TimezoneInfo(hour, minute) + return datetime.datetime( + year=dt[0], month=dt[1], day=dt[2], + hour=dt[3], minute=dt[4], second=dt[5], + microsecond=us, tzinfo=tz) + except Exception: + raise ValueError(f"Error in RFC339 Date Formatting {s}") def format_rfc3339(date_time): if date_time.tzinfo is None: diff --git a/kubernetes/test/test_api_client.py b/kubernetes/test/test_api_client.py index 486b4ac5b8..375963e7eb 100644 --- a/kubernetes/test/test_api_client.py +++ b/kubernetes/test/test_api_client.py @@ -8,6 +8,8 @@ import kubernetes from kubernetes.client.configuration import Configuration import urllib3 +import datetime +from kubernetes.config import dateutil as kube_dateutil class TestApiClient(unittest.TestCase): @@ -49,3 +51,30 @@ def test_rest_proxycare(self): # test client = kubernetes.client.ApiClient(configuration=config) self.assertEqual( expected_pool, type(client.rest_client.pool_manager) ) + + def test_1_parse_rfc3339(self): + dt = datetime.datetime(2023, 1, 1, 12, 0, 0) + result = kube_dateutil.parse_rfc3339(dt) + self.assertIsNotNone(result.tzinfo) + + def test_2_parse_rfc3339(self): + """Test that invalid RFC3339 strings raise ValueError with descriptive message""" + invalid_inputs = [ + "invalid-datetime-string", + "", + "not-a-date", + "2023", # incomplete + "random text", + "2023-13-01T12:00:00Z", # invalid month + "not-rfc3339-format" + ] + + for invalid_input in invalid_inputs: + with self.subTest(input=invalid_input): + with self.assertRaises(ValueError) as context: + kube_dateutil.parse_rfc3339(invalid_input) + + # Check that the error message includes the invalid input + error_message = str(context.exception) + self.assertIn("Error in RFC339 Date Formatting", error_message) + self.assertIn(invalid_input, error_message) \ No newline at end of file