diff --git a/tests/test_api.py b/tests/test_api.py index 339541ff..c0c40ba4 100755 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -425,6 +425,12 @@ def test_metadata_root(self): with self.assertRaises(KeyError): root.signed.remove_key('root', 'nosuchkey') + # Test serializing and deserializing without consistent_snapshot. + root_dict = root.to_dict() + del root_dict["signed"]["consistent_snapshot"] + root = Root.from_dict(copy.deepcopy(root_dict["signed"])) + self.assertEqual(root_dict["signed"], root.to_dict()) + def test_delegated_role_class(self): roles = [ { diff --git a/tuf/api/metadata.py b/tuf/api/metadata.py index 95036b1f..47e01ba6 100644 --- a/tuf/api/metadata.py +++ b/tuf/api/metadata.py @@ -503,8 +503,8 @@ class Root(Signed): """A container for the signed part of root metadata. Attributes: - consistent_snapshot: A boolean indicating whether the repository - supports consistent snapshots. + consistent_snapshot: An optional boolean indicating whether the + repository supports consistent snapshots. keys: A dictionary that contains a public key store used to verify top level roles metadata signatures:: @@ -534,9 +534,9 @@ def __init__( version: int, spec_version: str, expires: datetime, - consistent_snapshot: bool, keys: Dict[str, Key], roles: Dict[str, Role], + consistent_snapshot: Optional[bool] = None, unrecognized_fields: Optional[Mapping[str, Any]] = None, ) -> None: super().__init__(version, spec_version, expires, unrecognized_fields) @@ -548,7 +548,7 @@ def __init__( def from_dict(cls, root_dict: Dict[str, Any]) -> "Root": """Creates Root object from its dict representation.""" common_args = cls._common_fields_from_dict(root_dict) - consistent_snapshot = root_dict.pop("consistent_snapshot") + consistent_snapshot = root_dict.pop("consistent_snapshot", None) keys = root_dict.pop("keys") roles = root_dict.pop("roles") @@ -558,7 +558,7 @@ def from_dict(cls, root_dict: Dict[str, Any]) -> "Root": roles[role_name] = Role.from_dict(role_dict) # All fields left in the root_dict are unrecognized. - return cls(*common_args, consistent_snapshot, keys, roles, root_dict) + return cls(*common_args, keys, roles, consistent_snapshot, root_dict) def to_dict(self) -> Dict[str, Any]: """Returns the dict representation of self.""" @@ -567,10 +567,11 @@ def to_dict(self) -> Dict[str, Any]: roles = {} for role_name, role in self.roles.items(): roles[role_name] = role.to_dict() + if self.consistent_snapshot is not None: + root_dict["consistent_snapshot"] = self.consistent_snapshot root_dict.update( { - "consistent_snapshot": self.consistent_snapshot, "keys": keys, "roles": roles, }