From 08462b119a3e21a069b24c6dee3fe0b22cab072f Mon Sep 17 00:00:00 2001 From: Nicolas Thumann Date: Mon, 11 Dec 2023 10:22:22 +0100 Subject: [PATCH] Change: Assume UTC when no offset it specified (#941) * Change: Assume UTC when no offset it specified * Fix: Unit tests --- pontos/models/__init__.py | 11 +++++------ tests/models/test_models.py | 13 ++++++++++--- tests/nvd/cpe/test_api.py | 10 +++++++--- tests/nvd/cve/test_api.py | 8 +++++--- tests/nvd/cve_changes/test_api.py | 3 ++- tests/nvd/models/test_cpe.py | 10 +++++++--- tests/nvd/models/test_cve.py | 12 ++++++++---- tests/nvd/models/test_cve_change.py | 5 +++-- 8 files changed, 47 insertions(+), 25 deletions(-) diff --git a/pontos/models/__init__.py b/pontos/models/__init__.py index ce432e4b3..1402720d8 100644 --- a/pontos/models/__init__.py +++ b/pontos/models/__init__.py @@ -16,7 +16,7 @@ # along with this program. If not, see . from dataclasses import dataclass -from datetime import date, datetime +from datetime import date, datetime, timezone from enum import Enum from inspect import isclass from typing import Any, Dict, Type, Union, get_args, get_origin, get_type_hints @@ -93,11 +93,10 @@ def _get_value_from_model_field_cls( value = dateparser.isoparse(value) # the iso format may not contain UTC data or a UTC offset # this means it is considered local time (Python calls this "naive" - # datetime) and can't really be compared to other times. maybe we - # should always assume UTC for these formats. - # This could be done the following: - # if not value.tzinfo: - # value = value.replace(tzinfo=timezone.utc) + # datetime) and can't really be compared to other times. + # Let's UTC in these cases: + if not value.tzinfo: + value = value.replace(tzinfo=timezone.utc) elif isclass(model_field_cls) and issubclass(model_field_cls, date): value = date.fromisoformat(value) elif get_origin(model_field_cls) == list: diff --git a/tests/models/test_models.py b/tests/models/test_models.py index e826dfa6b..cea2c1906 100644 --- a/tests/models/test_models.py +++ b/tests/models/test_models.py @@ -112,7 +112,9 @@ class ExampleModel(Model): foo: datetime model = ExampleModel.from_dict({"foo": "1988-10-01T04:00:00.000"}) - self.assertEqual(model.foo, datetime(1988, 10, 1, 4)) + self.assertEqual( + model.foo, datetime(1988, 10, 1, 4, tzinfo=timezone.utc) + ) model = ExampleModel.from_dict({"foo": "1988-10-01T04:00:00Z"}) self.assertEqual( @@ -131,7 +133,10 @@ class ExampleModel(Model): ) model = ExampleModel.from_dict({"foo": "2021-06-06T11:15:10.213"}) - self.assertEqual(model.foo, datetime(2021, 6, 6, 11, 15, 10, 213000)) + self.assertEqual( + model.foo, + datetime(2021, 6, 6, 11, 15, 10, 213000, tzinfo=timezone.utc), + ) def test_date(self): @dataclass @@ -190,7 +195,9 @@ class ExampleModel(Model): ) self.assertEqual(model.foo, "abc") - self.assertEqual(model.bar, datetime(1988, 10, 1, 4)) + self.assertEqual( + model.bar, datetime(1988, 10, 1, 4, tzinfo=timezone.utc) + ) self.assertEqual(model.id, 123) self.assertEqual(model.baz, ["a", "b", "c"]) self.assertIsNotNone(model.ipsum) diff --git a/tests/nvd/cpe/test_api.py b/tests/nvd/cpe/test_api.py index 07a7ad51b..bc0ba5d81 100644 --- a/tests/nvd/cpe/test_api.py +++ b/tests/nvd/cpe/test_api.py @@ -18,7 +18,7 @@ # pylint: disable=line-too-long, arguments-differ, redefined-builtin # ruff: noqa: E501 -from datetime import datetime +from datetime import datetime, timezone from itertools import repeat from typing import Any, Optional from unittest.mock import MagicMock, patch @@ -132,9 +132,13 @@ async def test_cpe(self): self.assertEqual(cpe.cpe_name_id, uuid_replace(uuid, 1, 1)) self.assertFalse(cpe.deprecated) self.assertEqual( - cpe.last_modified, datetime(2022, 12, 9, 18, 15, 16, 973000) + cpe.last_modified, + datetime(2022, 12, 9, 18, 15, 16, 973000, tzinfo=timezone.utc), + ) + self.assertEqual( + cpe.created, + datetime(2022, 12, 9, 16, 20, 6, 943000, tzinfo=timezone.utc), ) - self.assertEqual(cpe.created, datetime(2022, 12, 9, 16, 20, 6, 943000)) self.assertEqual(cpe.refs, []) self.assertEqual(cpe.titles, []) diff --git a/tests/nvd/cve/test_api.py b/tests/nvd/cve/test_api.py index bf6c63d8a..e131f6932 100644 --- a/tests/nvd/cve/test_api.py +++ b/tests/nvd/cve/test_api.py @@ -17,7 +17,7 @@ # pylint: disable=line-too-long, arguments-differ, redefined-builtin -from datetime import datetime +from datetime import datetime, timezone from typing import Any, Dict, List, Optional from unittest.mock import MagicMock, patch @@ -111,10 +111,12 @@ async def test_cve(self): self.assertEqual(cve.id, "CVE-2022-45536") self.assertEqual(cve.source_identifier, "cve@mitre.org") self.assertEqual( - cve.published, datetime(2022, 11, 22, 21, 15, 11, 103000) + cve.published, + datetime(2022, 11, 22, 21, 15, 11, 103000, tzinfo=timezone.utc), ) self.assertEqual( - cve.last_modified, datetime(2022, 11, 23, 16, 2, 7, 367000) + cve.last_modified, + datetime(2022, 11, 23, 16, 2, 7, 367000, tzinfo=timezone.utc), ) self.assertEqual(len(cve.descriptions), 1) self.assertEqual(len(cve.references), 2) diff --git a/tests/nvd/cve_changes/test_api.py b/tests/nvd/cve_changes/test_api.py index f4e4ca3ca..c261e5070 100644 --- a/tests/nvd/cve_changes/test_api.py +++ b/tests/nvd/cve_changes/test_api.py @@ -61,7 +61,8 @@ async def test_cve_changes(self): ) self.assertEqual(cve_change.source_identifier, "nvd@nist.gov") self.assertEqual( - cve_change.created, datetime(2022, 3, 18, 20, 13, 8, 123000) + cve_change.created, + datetime(2022, 3, 18, 20, 13, 8, 123000, tzinfo=timezone.utc), ) self.assertEqual( cve_change.details, diff --git a/tests/nvd/models/test_cpe.py b/tests/nvd/models/test_cpe.py index 1bb7cb758..c6a59ea21 100644 --- a/tests/nvd/models/test_cpe.py +++ b/tests/nvd/models/test_cpe.py @@ -17,7 +17,7 @@ # ruff: noqa: E501 import unittest -from datetime import datetime +from datetime import datetime, timezone from uuid import UUID from pontos.nvd.models.cpe import CPE, ReferenceType @@ -37,9 +37,13 @@ def test_required_only(self): ) self.assertFalse(cpe.deprecated) self.assertEqual( - cpe.last_modified, datetime(2022, 12, 9, 18, 15, 16, 973000) + cpe.last_modified, + datetime(2022, 12, 9, 18, 15, 16, 973000, tzinfo=timezone.utc), + ) + self.assertEqual( + cpe.created, + datetime(2022, 12, 9, 16, 20, 6, 943000, tzinfo=timezone.utc), ) - self.assertEqual(cpe.created, datetime(2022, 12, 9, 16, 20, 6, 943000)) self.assertEqual(cpe.titles, []) self.assertEqual(cpe.refs, []) diff --git a/tests/nvd/models/test_cve.py b/tests/nvd/models/test_cve.py index c7a2d1b12..273c85c55 100644 --- a/tests/nvd/models/test_cve.py +++ b/tests/nvd/models/test_cve.py @@ -19,7 +19,7 @@ # ruff: noqa: E501 import unittest -from datetime import date, datetime +from datetime import date, datetime, timezone from pontos.nvd.models import cvss_v2, cvss_v3 from pontos.nvd.models.cve import CVE, CVSSType, Operator @@ -33,10 +33,12 @@ def test_required_only(self): self.assertEqual(cve.id, "CVE-2022-45536") self.assertEqual(cve.source_identifier, "cve@mitre.org") self.assertEqual( - cve.published, datetime(2022, 11, 22, 21, 15, 11, 103000) + cve.published, + datetime(2022, 11, 22, 21, 15, 11, 103000, tzinfo=timezone.utc), ) self.assertEqual( - cve.last_modified, datetime(2022, 11, 23, 16, 2, 7, 367000) + cve.last_modified, + datetime(2022, 11, 23, 16, 2, 7, 367000, tzinfo=timezone.utc), ) self.assertEqual(len(cve.descriptions), 1) self.assertEqual(len(cve.references), 2) @@ -506,7 +508,9 @@ def test_vendor_comments(self): comment.comment, "Fixed in Apache HTTP Server 1.3.12:\nhttp://httpd.apache.org/security/vulnerabilities_13.html", ) - self.assertEqual(comment.last_modified, datetime(2008, 7, 2)) + self.assertEqual( + comment.last_modified, datetime(2008, 7, 2, tzinfo=timezone.utc) + ) def test_evaluator_comment(self): cve = CVE.from_dict( diff --git a/tests/nvd/models/test_cve_change.py b/tests/nvd/models/test_cve_change.py index d8c8664ae..e34acc2b4 100644 --- a/tests/nvd/models/test_cve_change.py +++ b/tests/nvd/models/test_cve_change.py @@ -6,7 +6,7 @@ # ruff: noqa: E501 import unittest -from datetime import datetime +from datetime import datetime, timezone from uuid import UUID from pontos.nvd.models.cve_change import CVEChange, Detail, EventName @@ -25,7 +25,8 @@ def test_required_only(self): ) self.assertEqual(cve_change.source_identifier, "nvd@nist.gov") self.assertEqual( - cve_change.created, datetime(2022, 3, 18, 20, 13, 8, 123000) + cve_change.created, + datetime(2022, 3, 18, 20, 13, 8, 123000, tzinfo=timezone.utc), ) self.assertEqual( cve_change.details,