Skip to content

Commit a17ceda

Browse files
author
Martin Vrachev
committed
Add "validation" arg in JSONSerializer
If the "validation" argument is set then when serializing the metadata object will be validated. Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
1 parent 5d24956 commit a17ceda

3 files changed

Lines changed: 29 additions & 5 deletions

File tree

tests/test_api.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
Targets,
4040
Timestamp,
4141
)
42-
from tuf.api.serialization import DeserializationError
42+
from tuf.api.serialization import DeserializationError, SerializationError
4343
from tuf.api.serialization.json import CanonicalJSONSerializer, JSONSerializer
4444

4545
logger = logging.getLogger(__name__)
@@ -157,6 +157,13 @@ def test_read_write_read_compare(self) -> None:
157157

158158
os.remove(path_2)
159159

160+
def test_serialize_with_validate(self) -> None:
161+
# Assert that by changing one required attribute validation will fail.
162+
root = Metadata.from_file(f"{self.repo_dir}/metadata/root.json")
163+
root.signed.version = 0
164+
with self.assertRaises(SerializationError):
165+
root.to_bytes(JSONSerializer(validate=True))
166+
160167
def test_to_from_bytes(self) -> None:
161168
for metadata in TOP_LEVEL_ROLE_NAMES:
162169
path = os.path.join(self.repo_dir, "metadata", metadata + ".json")

tests/test_trusted_metadata_set.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
Targets,
2323
Timestamp,
2424
)
25+
from tuf.api.serialization.json import JSONSerializer
2526
from tuf.ngclient._internal.trusted_metadata_set import TrustedMetadataSet
2627

2728
logger = logging.getLogger(__name__)
@@ -49,7 +50,7 @@ def modify_metadata(
4950
metadata = Metadata.from_bytes(cls.metadata[rolename])
5051
modification_func(metadata.signed)
5152
metadata.sign(cls.keystore[rolename])
52-
return metadata.to_bytes()
53+
return metadata.to_bytes(JSONSerializer(validate=True))
5354

5455
@classmethod
5556
def setUpClass(cls) -> None:

tuf/api/serialization/json.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"""
1010

1111
import json
12+
from typing import Optional
1213

1314
from securesystemslib.formats import encode_canonical
1415

@@ -44,17 +45,22 @@ def deserialize(self, raw_data: bytes) -> Metadata:
4445
class JSONSerializer(MetadataSerializer):
4546
"""Provides Metadata to JSON serialize method.
4647
47-
Attributes:
48+
Args:
4849
compact: A boolean indicating if the JSON bytes generated in
49-
'serialize' should be compact by excluding whitespace.
50+
'serialize' should be compact by excluding whitespace.
51+
validate: Check that the metadata object can be deserialized again
52+
without change of contents and thus find common mistakes.
53+
This validation might slow down serialization significantly.
5054
5155
"""
5256

53-
def __init__(self, compact: bool = False):
57+
def __init__(self, compact: bool = False, validate: Optional[bool] = False):
5458
self.compact = compact
59+
self.validate = validate
5560

5661
def serialize(self, metadata_obj: Metadata) -> bytes:
5762
"""Serialize Metadata object into utf-8 encoded JSON bytes."""
63+
5864
try:
5965
indent = None if self.compact else 1
6066
separators = (",", ":") if self.compact else (",", ": ")
@@ -65,6 +71,16 @@ def serialize(self, metadata_obj: Metadata) -> bytes:
6571
sort_keys=True,
6672
).encode("utf-8")
6773

74+
if self.validate:
75+
try:
76+
new_md_obj = JSONDeserializer().deserialize(json_bytes)
77+
if metadata_obj != new_md_obj:
78+
raise ValueError(
79+
"Metadata changes if you serialize and deserialize."
80+
)
81+
except Exception as e:
82+
raise ValueError("Metadata cannot be validated!") from e
83+
6884
except Exception as e:
6985
raise SerializationError from e
7086

0 commit comments

Comments
 (0)