Skip to content

Commit a347d03

Browse files
author
Lukas Pühringer
authored
Merge pull request #1809 from MVrachev/signatures-tests
Add Metadata.signatures serialization tests
2 parents 3b135d7 + 17503eb commit a347d03

4 files changed

Lines changed: 79 additions & 21 deletions

File tree

requirements-pinned.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@ idna==3.3 # via requests
66
pycparser==2.21 # via cffi
77
pynacl==1.5.0 # via securesystemslib
88
requests==2.27.1
9-
securesystemslib[crypto,pynacl]==0.21.0
9+
securesystemslib[crypto,pynacl]==0.22.0
1010
six==1.16.0 # via pynacl, securesystemslib
1111
urllib3==1.26.8 # via requests

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ packages = find:
3737
python_requires = ~=3.7
3838
install_requires =
3939
requests>=2.19.1
40-
securesystemslib>=0.20.0
40+
securesystemslib>=0.22.0
4141

4242
[options.packages.find]
4343
exclude = tests

tests/test_api.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ def test_verify_failures(self) -> None:
276276
timestamp_key.verify_signature(md_obj)
277277
sig.signature = correct_sig
278278

279-
def test_metadata_base(self) -> None:
279+
def test_metadata_signed_is_expired(self) -> None:
280280
# Use of Snapshot is arbitrary, we're just testing the base class
281281
# features with real data
282282
snapshot_path = os.path.join(self.repo_dir, "metadata", "snapshot.json")
@@ -303,14 +303,6 @@ def test_metadata_base(self) -> None:
303303
self.assertFalse(is_expired)
304304
md.signed.expires = expires
305305

306-
# Test deserializing metadata with non-unique signatures:
307-
data = md.to_dict()
308-
data["signatures"].append(
309-
{"keyid": data["signatures"][0]["keyid"], "sig": "foo"}
310-
)
311-
with self.assertRaises(ValueError):
312-
Metadata.from_dict(data)
313-
314306
def test_metadata_verify_delegate(self) -> None:
315307
root_path = os.path.join(self.repo_dir, "metadata", "root.json")
316308
root = Metadata[Root].from_file(root_path)

tests/test_metadata_serialization.py

Lines changed: 76 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,14 @@
1212
import sys
1313
import unittest
1414

15+
from securesystemslib.signer import Signature
16+
1517
from tests import utils
1618
from tuf.api.metadata import (
1719
DelegatedRole,
1820
Delegations,
1921
Key,
22+
Metadata,
2023
MetaFile,
2124
Role,
2225
Root,
@@ -25,13 +28,76 @@
2528
Targets,
2629
Timestamp,
2730
)
31+
from tuf.api.serialization import DeserializationError
2832

2933
logger = logging.getLogger(__name__)
3034

3135

36+
# pylint: disable=too-many-public-methods
3237
class TestSerialization(unittest.TestCase):
3338
"""Test serialization for all classes in 'tuf/api/metadata.py'."""
3439

40+
invalid_metadata: utils.DataSet = {
41+
"no signatures field": b'{"signed": \
42+
{ "_type": "timestamp", "spec_version": "1.0.0", "version": 1, "expires": "2030-01-01T00:00:00Z", \
43+
"meta": {"snapshot.json": {"hashes": {"sha256" : "abc"}, "version": 1}}} \
44+
}',
45+
"non unique duplicating signatures": b'{"signed": \
46+
{ "_type": "timestamp", "spec_version": "1.0.0", "version": 1, "expires": "2030-01-01T00:00:00Z", \
47+
"meta": {"snapshot.json": {"hashes": {"sha256" : "abc"}, "version": 1}}}, \
48+
"signatures": [{"keyid": "id", "sig": "b"}, {"keyid": "id", "sig": "b"}] \
49+
}',
50+
}
51+
52+
@utils.run_sub_tests_with_dataset(invalid_metadata)
53+
def test_invalid_metadata_serialization(self, test_data: bytes) -> None:
54+
# We expect a DeserializationError reraised from ValueError or KeyError.
55+
with self.assertRaises(DeserializationError):
56+
Metadata.from_bytes(test_data)
57+
58+
valid_metadata: utils.DataSet = {
59+
"multiple signatures": b'{ \
60+
"signed": \
61+
{ "_type": "timestamp", "spec_version": "1.0.0", "version": 1, "expires": "2030-01-01T00:00:00Z", \
62+
"meta": {"snapshot.json": {"hashes": {"sha256" : "abc"}, "version": 1}}}, \
63+
"signatures": [{ "keyid": "id", "sig": "b"}, {"keyid": "id2", "sig": "d" }] \
64+
}',
65+
"no signatures": b'{ \
66+
"signed": \
67+
{ "_type": "timestamp", "spec_version": "1.0.0", "version": 1, "expires": "2030-01-01T00:00:00Z", \
68+
"meta": {"snapshot.json": {"hashes": {"sha256" : "abc"}, "version": 1}}}, \
69+
"signatures": [] \
70+
}',
71+
}
72+
73+
@utils.run_sub_tests_with_dataset(valid_metadata)
74+
def test_valid_metadata_serialization(self, test_case_data: bytes) -> None:
75+
md = Metadata.from_bytes(test_case_data)
76+
input_dict = json.loads(test_case_data)
77+
self.assertDictEqual(input_dict, md.to_dict())
78+
79+
invalid_signatures: utils.DataSet = {
80+
"missing keyid attribute in a signature": '{ "sig": "abc" }',
81+
"missing sig attribute in a signature": '{ "keyid": "id" }',
82+
}
83+
84+
@utils.run_sub_tests_with_dataset(invalid_signatures)
85+
def test_invalid_signature_serialization(self, test_data: str) -> None:
86+
case_dict = json.loads(test_data)
87+
with self.assertRaises(KeyError):
88+
Signature.from_dict(case_dict)
89+
90+
valid_signatures: utils.DataSet = {
91+
"all": '{ "keyid": "id", "sig": "b"}',
92+
"unrecognized fields": '{ "keyid": "id", "sig": "b", "foo": "bar"}',
93+
}
94+
95+
@utils.run_sub_tests_with_dataset(valid_signatures)
96+
def test_signature_serialization(self, test_case_data: str) -> None:
97+
case_dict = json.loads(test_case_data)
98+
signature = Signature.from_dict(copy.copy(case_dict))
99+
self.assertEqual(case_dict, signature.to_dict())
100+
35101
# Snapshot instances with meta = {} are valid, but for a full valid
36102
# repository it's required that meta has at least one element inside it.
37103
invalid_signed: utils.DataSet = {
@@ -56,7 +122,7 @@ class TestSerialization(unittest.TestCase):
56122
def test_invalid_signed_serialization(self, test_case_data: str) -> None:
57123
case_dict = json.loads(test_case_data)
58124
with self.assertRaises((KeyError, ValueError, TypeError)):
59-
Snapshot.from_dict(copy.deepcopy(case_dict))
125+
Snapshot.from_dict(case_dict)
60126

61127
valid_keys: utils.DataSet = {
62128
"all": '{"keytype": "rsa", "scheme": "rsassa-pss-sha256", \
@@ -89,7 +155,7 @@ def test_invalid_key_serialization(self, test_case_data: str) -> None:
89155
case_dict = json.loads(test_case_data)
90156
with self.assertRaises((TypeError, KeyError)):
91157
keyid = case_dict.pop("keyid")
92-
Key.from_dict(keyid, copy.copy(case_dict))
158+
Key.from_dict(keyid, case_dict)
93159

94160
invalid_roles: utils.DataSet = {
95161
"no threshold": '{"keyids": ["keyid"]}',
@@ -103,7 +169,7 @@ def test_invalid_key_serialization(self, test_case_data: str) -> None:
103169
def test_invalid_role_serialization(self, test_case_data: str) -> None:
104170
case_dict = json.loads(test_case_data)
105171
with self.assertRaises((KeyError, TypeError, ValueError)):
106-
Role.from_dict(copy.deepcopy(case_dict))
172+
Role.from_dict(case_dict)
107173

108174
valid_roles: utils.DataSet = {
109175
"all": '{"keyids": ["keyid"], "threshold": 3}',
@@ -201,7 +267,7 @@ def test_root_serialization(self, test_case_data: str) -> None:
201267
"snapshot": {"keyids": ["keyid2"], "threshold": 1}, \
202268
"foo": {"keyids": ["keyid2"], "threshold": 1}} \
203269
}',
204-
"invalid expiry with microsecond s": '{"_type": "root", "spec_version": "1.0.0", "version": 1, \
270+
"invalid expiry with microseconds": '{"_type": "root", "spec_version": "1.0.0", "version": 1, \
205271
"expires": "2030-01-01T12:00:00.123456Z", "consistent_snapshot": false, \
206272
"keys": {}, "roles": {"root": {}, "timestamp": {}, "targets": {}, "snapshot": {}}}',
207273
}
@@ -210,7 +276,7 @@ def test_root_serialization(self, test_case_data: str) -> None:
210276
def test_invalid_root_serialization(self, test_case_data: str) -> None:
211277
case_dict = json.loads(test_case_data)
212278
with self.assertRaises(ValueError):
213-
Root.from_dict(copy.deepcopy(case_dict))
279+
Root.from_dict(case_dict)
214280

215281
invalid_metafiles: utils.DataSet = {
216282
"wrong length type": '{"version": 1, "length": "a", "hashes": {"sha256" : "abc"}}',
@@ -226,7 +292,7 @@ def test_invalid_root_serialization(self, test_case_data: str) -> None:
226292
def test_invalid_metafile_serialization(self, test_case_data: str) -> None:
227293
case_dict = json.loads(test_case_data)
228294
with self.assertRaises((TypeError, ValueError, AttributeError)):
229-
MetaFile.from_dict(copy.deepcopy(case_dict))
295+
MetaFile.from_dict(case_dict)
230296

231297
valid_metafiles: utils.DataSet = {
232298
"all": '{"hashes": {"sha256" : "abc"}, "length": 12, "version": 1}',
@@ -250,7 +316,7 @@ def test_metafile_serialization(self, test_case_data: str) -> None:
250316
def test_invalid_timestamp_serialization(self, test_case_data: str) -> None:
251317
case_dict = json.loads(test_case_data)
252318
with self.assertRaises((ValueError, KeyError)):
253-
Timestamp.from_dict(copy.deepcopy(case_dict))
319+
Timestamp.from_dict(case_dict)
254320

255321
valid_timestamps: utils.DataSet = {
256322
"all": '{ "_type": "timestamp", "spec_version": "1.0.0", "version": 1, "expires": "2030-01-01T00:00:00Z", \
@@ -326,7 +392,7 @@ def test_invalid_delegated_role_serialization(
326392
) -> None:
327393
case_dict = json.loads(test_case_data)
328394
with self.assertRaises(ValueError):
329-
DelegatedRole.from_dict(copy.copy(case_dict))
395+
DelegatedRole.from_dict(case_dict)
330396

331397
invalid_delegations: utils.DataSet = {
332398
"empty delegations": "{}",
@@ -387,7 +453,7 @@ def test_invalid_delegation_serialization(
387453
) -> None:
388454
case_dict = json.loads(test_case_data)
389455
with self.assertRaises((ValueError, KeyError, AttributeError)):
390-
Delegations.from_dict(copy.deepcopy(case_dict))
456+
Delegations.from_dict(case_dict)
391457

392458
valid_delegations: utils.DataSet = {
393459
"all": '{"keys": { \
@@ -424,7 +490,7 @@ def test_invalid_targetfile_serialization(
424490
) -> None:
425491
case_dict = json.loads(test_case_data)
426492
with self.assertRaises(KeyError):
427-
TargetFile.from_dict(copy.deepcopy(case_dict), "file1.txt")
493+
TargetFile.from_dict(case_dict, "file1.txt")
428494

429495
valid_targetfiles: utils.DataSet = {
430496
"all": '{"length": 12, "hashes": {"sha256" : "abc"}, \

0 commit comments

Comments
 (0)